/** * @brief This function send nb_data pointed with *buf with the pipe number specified * * * @param pipe * @param nb_data * @param buf * @param handle call back function pointer * * @return status */ U8 host_send_data_interrupt(U8 pipe, U16 nb_data, U8 *buf, void(*handle)(U8 status, U16 nb_byte)) { U8 i; U8 *ptr_buf=buf; Host_select_pipe(pipe); if(it_pipe_str[pipe].enable==ENABLE) { return HOST_FALSE; } else { if(is_any_interrupt_pipe_active()==FALSE) { g_sav_int_sof_enable=Is_host_sof_interrupt_enabled(); Host_enable_sof_interrupt(); } it_pipe_str[pipe].enable=ENABLE; it_pipe_str[pipe].nb_byte_to_process=nb_data; it_pipe_str[pipe].nb_byte_processed=0; it_pipe_str[pipe].ptr_buf=buf; it_pipe_str[pipe].handle=handle; it_pipe_str[pipe].timeout=0; it_pipe_str[pipe].nak_timeout=NAK_SEND_TIMEOUT; it_pipe_str[pipe].nb_byte_on_going=0; Host_reset_pipe(pipe); Host_unfreeze_pipe(); // Prepare data to be sent i = Host_get_pipe_length(); if ( i > nb_data) // Pipe size> remaining data { i = nb_data; nb_data = 0; } else // Pipe size < remaining data { nb_data -= i; } it_pipe_str[pipe].nb_byte_on_going+=i; // Update nb data processed while (i!=0) // Load Pipe buffer { Host_write_byte(*ptr_buf++); i--; } private_sof_counter=0; // Reset the counter in SOF detection sub-routine it_pipe_str[pipe].timeout=0; // Refresh timeout counter Host_ack_out_sent(); Host_ack_stall(); Host_ack_nak_received(); Host_enable_stall_interrupt(); Host_enable_error_interrupt(); #if (NAK_TIMEOUT_ENABLE==ENABLE) Host_enable_nak_interrupt(); #endif Host_enable_transmit_interrupt(); Host_send_out(); // Send the USB frame return HOST_TRUE; } }
//! //! @brief This function sends nb_data bytes pointed to by ptr_buf on the specified pipe. //! //! @param pipe //! @param nb_data //! @param ptr_buf //! @param handler Call-back function pointer //! //! @return bool: Status //! bool host_send_data_interrupt(uint8_t pipe, uint16_t nb_data, const void *ptr_buf, Pipe_handler *handler) { bool sav_glob_int_en; if (it_pipe_str[pipe].enable) return false; if (!is_any_interrupt_pipe_active()) { g_sav_int_sof_enable = Is_host_sof_interrupt_enabled(); Host_enable_sof_interrupt(); } it_pipe_str[pipe].enable = true; it_pipe_str[pipe].nb_byte_to_process = nb_data; it_pipe_str[pipe].nb_byte_processed = 0; it_pipe_str[pipe].ptr_buf = (void *)ptr_buf; it_pipe_str[pipe].handler = handler; it_pipe_str[pipe].timeout = 0; it_pipe_str[pipe].nak_timeout = NAK_SEND_TIMEOUT; if ((sav_glob_int_en = cpu_irq_is_enabled())) cpu_irq_disable(); Host_reset_pipe(pipe); (void)Is_host_resetting_pipe(pipe); if (sav_glob_int_en) cpu_irq_enable(); Host_configure_pipe_token(pipe, TOKEN_OUT); Host_ack_out_ready(pipe); Host_unfreeze_pipe(pipe); // Prepare data to be sent Host_reset_pipe_fifo_access(pipe); it_pipe_str[pipe].nb_byte_on_going = nb_data - host_write_p_txpacket(pipe, ptr_buf, nb_data, NULL); private_sof_counter = 0; // Reset the counter in SOF detection subroutine it_pipe_str[pipe].timeout = 0; // Refresh time-out counter if ((sav_glob_int_en = cpu_irq_is_enabled())) cpu_irq_disable(); Host_ack_out_ready(pipe); Host_ack_stall(pipe); Host_ack_nak_received(pipe); (void)Is_host_nak_received(pipe); if (sav_glob_int_en) cpu_irq_enable(); Host_enable_stall_interrupt(pipe); Host_enable_pipe_error_interrupt(pipe); #if NAK_TIMEOUT_ENABLE == ENABLE Host_enable_nak_received_interrupt(pipe); #endif Host_enable_out_ready_interrupt(pipe); Host_enable_pipe_interrupt(pipe); Host_send_out(pipe); // Send the USB frame return true; }
//! //! @brief This function receives nb_data bytes pointed to by ptr_buf on the specified pipe. //! //! *nb_data is updated with the final number of data bytes received. //! //! @param pipe //! @param nb_data //! @param ptr_buf //! @param handler Call-back function pointer //! //! @return bool: Status //! bool host_get_data_interrupt(uint8_t pipe, uint16_t nb_data, void *ptr_buf, Pipe_handler *handler) { bool sav_glob_int_en; if (it_pipe_str[pipe].enable) return false; if (!is_any_interrupt_pipe_active()) { g_sav_int_sof_enable = Is_host_sof_interrupt_enabled(); Host_enable_sof_interrupt(); } it_pipe_str[pipe].enable = true; it_pipe_str[pipe].nb_byte_to_process = nb_data; it_pipe_str[pipe].nb_byte_processed = 0; it_pipe_str[pipe].ptr_buf = ptr_buf; it_pipe_str[pipe].handler = handler; it_pipe_str[pipe].timeout = 0; it_pipe_str[pipe].nak_timeout = NAK_RECEIVE_TIMEOUT; private_sof_counter = 0; // Reset the counter in SOF detection subroutine if ((sav_glob_int_en = cpu_irq_is_enabled())) cpu_irq_disable(); Host_reset_pipe(pipe); Host_ack_stall(pipe); Host_ack_nak_received(pipe); (void)Is_host_nak_received(pipe); if (sav_glob_int_en) cpu_irq_enable(); Host_enable_stall_interrupt(pipe); #if NAK_TIMEOUT_ENABLE == ENABLE Host_enable_nak_received_interrupt(pipe); #endif Host_enable_pipe_error_interrupt(pipe); Host_enable_in_received_interrupt(pipe); Host_enable_pipe_interrupt(pipe); Host_enable_continuous_in_mode(pipe); Host_configure_pipe_token(pipe, TOKEN_IN); Host_ack_in_received(pipe); Host_unfreeze_pipe(pipe); return true; }
/** * @brief This function receives nb_data pointed with *buf with the pipe number specified * * The nb_data parameter is passed as a U16 pointer, thus the data pointed by this pointer * is updated with the final number of data byte received. * * @param pipe * @param nb_data * @param buf * @param handle call back function pointer * * @return status */ U8 host_get_data_interrupt(U8 pipe, U16 nb_data, U8 *buf,void(*handle)(U8 status, U16 nb_byte)) { Host_select_pipe(pipe); if(it_pipe_str[pipe].enable==ENABLE) { return HOST_FALSE; } else { if(is_any_interrupt_pipe_active()==FALSE) { g_sav_int_sof_enable=Is_host_sof_interrupt_enabled(); Host_enable_sof_interrupt(); } it_pipe_str[pipe].enable=ENABLE; it_pipe_str[pipe].nb_byte_to_process=nb_data; it_pipe_str[pipe].nb_byte_processed=0; it_pipe_str[pipe].ptr_buf=buf; it_pipe_str[pipe].handle=handle; it_pipe_str[pipe].timeout=0; it_pipe_str[pipe].nak_timeout=NAK_RECEIVE_TIMEOUT; private_sof_counter=0; // Reset the counter in SOF detection sub-routine Host_reset_pipe(pipe); Host_enable_stall_interrupt(); #if (NAK_TIMEOUT_ENABLE==ENABLE) Host_enable_nak_interrupt(); #endif Host_enable_error_interrupt(); Host_enable_receive_interrupt(); Host_ack_stall(); Host_ack_nak_received(); Host_continuous_in_mode(); Host_set_token_in(); Host_ack_in_received(); Host_unfreeze_pipe(); return HOST_TRUE; } }
__interrupt #endif static void usb_general_interrupt(void) #endif { #ifdef FREERTOS_USED portBASE_TYPE task_woken = pdFALSE; #endif #if USB_HOST_FEATURE == true && USB_HOST_PIPE_INTERRUPT_TRANSFER == ENABLE U8 i; #endif // ---------- DEVICE/HOST events management ------------------------------------ #if USB_DEVICE_FEATURE == true && USB_HOST_FEATURE == true // ID pin change detection if (Is_usb_id_transition() && Is_usb_id_interrupt_enabled()) { g_usb_mode = (Is_usb_id_device()) ? USB_MODE_DEVICE : USB_MODE_HOST; Usb_ack_id_transition(); if (g_usb_mode != g_old_usb_mode) // Basic debounce { // Previously in device mode, check if disconnection was detected if (g_old_usb_mode == USB_MODE_DEVICE) { if (usb_connected) { // Device mode disconnection actions usb_connected = false; usb_configuration_nb = 0; Usb_vbus_off_action(); } } // Previously in host mode, check if disconnection was detected else if (Is_host_attached()) { // Host mode disconnection actions device_state = DEVICE_UNATTACHED; Host_device_disconnection_action(); } //LOG_STR(log_pin_id_changed); if (Is_usb_id_device() == USB_MODE_DEVICE) { LOG_STR(log_pin_id_changed_to_device); } else { LOG_STR(log_pin_id_changed_to_host); } Usb_send_event((Is_usb_device()) ? EVT_USB_DEVICE_FUNCTION : EVT_USB_HOST_FUNCTION); Usb_id_transition_action(); // Easier to recover from ID signal de-bounce and ID pin transitions by shutting down the USB and resetting state machine to re-init #if ID_PIN_CHANGE_SHUTDOWN_USB == ENABLE Usb_disable(); Usb_disable_otg_pad(); extern void UsbResetStateMachine(void); UsbResetStateMachine(); #ifdef FREERTOS_USED // Release the semaphore in order to start a new device/host task taskENTER_CRITICAL(); xSemaphoreGiveFromISR(usb_tsk_semphr, &task_woken); taskEXIT_CRITICAL(); #endif #endif #if ID_PIN_CHANGE_GENERATE_RESET == ENABLE Reset_CPU(); #endif } } #endif // End DEVICE/HOST FEATURE MODE // ---------- DEVICE events management ----------------------------------------- #if USB_DEVICE_FEATURE == true #if USB_HOST_FEATURE == true // If both device and host features are enabled, check if device mode is engaged // (accessing the USB registers of a non-engaged mode, even with load operations, // may corrupt USB FIFO data). if (Is_usb_device()) #endif { // VBus state detection if (Is_usb_vbus_transition() && Is_usb_vbus_interrupt_enabled()) { Usb_ack_vbus_transition(); if (Is_usb_vbus_high()) { usb_start_device(); Usb_send_event(EVT_USB_POWERED); Usb_vbus_on_action(); } else { Usb_unfreeze_clock(); Usb_detach(); usb_connected = false; usb_configuration_nb = 0; Usb_send_event(EVT_USB_UNPOWERED); Usb_vbus_off_action(); #ifdef FREERTOS_USED // Release the semaphore in order to start a new device/host task taskENTER_CRITICAL(); xSemaphoreGiveFromISR(usb_tsk_semphr, &task_woken); taskEXIT_CRITICAL(); #endif } } // Device Start-of-Frame received if (Is_usb_sof() && Is_usb_sof_interrupt_enabled()) { Usb_ack_sof(); Usb_sof_action(); } // Device Suspend event (no more USB activity detected) if (Is_usb_suspend() && Is_usb_suspend_interrupt_enabled()) { Usb_ack_suspend(); Usb_enable_wake_up_interrupt(); (void)Is_usb_wake_up_interrupt_enabled(); Usb_freeze_clock(); Usb_send_event(EVT_USB_SUSPEND); Usb_suspend_action(); } // Wake-up event (USB activity detected): Used to resume if (Is_usb_wake_up() && Is_usb_wake_up_interrupt_enabled()) { Usb_unfreeze_clock(); (void)Is_usb_clock_frozen(); Usb_ack_wake_up(); Usb_disable_wake_up_interrupt(); Usb_wake_up_action(); Usb_send_event(EVT_USB_WAKE_UP); } // Resume state bus detection if (Is_usb_resume() && Is_usb_resume_interrupt_enabled()) { Usb_disable_wake_up_interrupt(); Usb_ack_resume(); Usb_disable_resume_interrupt(); Usb_resume_action(); Usb_send_event(EVT_USB_RESUME); } // USB bus reset detection if (Is_usb_reset() && Is_usb_reset_interrupt_enabled()) { Usb_ack_reset(); usb_init_device(); Usb_reset_action(); Usb_send_event(EVT_USB_RESET); } } #endif // End DEVICE FEATURE MODE // ---------- HOST events management ------------------------------------------- #if USB_HOST_FEATURE == true #if USB_DEVICE_FEATURE == true // If both device and host features are enabled, check if host mode is engaged // (accessing the USB registers of a non-engaged mode, even with load operations, // may corrupt USB FIFO data). else #endif { // The device has been disconnected if (Is_host_device_disconnection() && Is_host_device_disconnection_interrupt_enabled()) { host_disable_all_pipes(); Host_ack_device_disconnection(); #if USB_HOST_PIPE_INTERRUPT_TRANSFER == ENABLE reset_it_pipe_str(); #endif device_state = DEVICE_UNATTACHED; LOG_STR(log_device_disconnected); Usb_send_event(EVT_HOST_DISCONNECTION); Host_device_disconnection_action(); #ifdef FREERTOS_USED // Release the semaphore in order to start a new device/host task taskENTER_CRITICAL(); xSemaphoreGiveFromISR(usb_tsk_semphr, &task_woken); taskEXIT_CRITICAL(); #endif } // Device connection if (Is_host_device_connection() && Is_host_device_connection_interrupt_enabled()) { Host_ack_device_connection(); host_disable_all_pipes(); Host_device_connection_action(); } // Host Start-of-Frame has been sent if (Is_host_sof() && Is_host_sof_interrupt_enabled()) { Host_ack_sof(); Usb_send_event(EVT_HOST_SOF); #if (USB_HIGH_SPEED_SUPPORT==true) if( Is_usb_full_speed_mode() ) { private_sof_counter++; }else{ private_sof_counter_HS++; if( 0 == (private_sof_counter_HS%8) ) { private_sof_counter++; } } #else private_sof_counter++; #endif // Delay time-out management for interrupt transfer mode in host mode #if USB_HOST_PIPE_INTERRUPT_TRANSFER == ENABLE && TIMEOUT_DELAY_ENABLE == ENABLE if (private_sof_counter >= 250) // Count 250 ms (SOF @ 1 ms) { private_sof_counter = 0; for (i = 0; i < MAX_PEP_NB; i++) { if (it_pipe_str[i].enable && ++it_pipe_str[i].timeout > TIMEOUT_DELAY && Host_get_pipe_type(i) != TYPE_INTERRUPT) { it_pipe_str[i].enable = false; it_pipe_str[i].status = PIPE_DELAY_TIMEOUT; Host_reset_pipe(i); if (!is_any_interrupt_pipe_active() && !g_sav_int_sof_enable) // If no more transfer is armed { Host_disable_sof_interrupt(); } it_pipe_str[i].handler(PIPE_DELAY_TIMEOUT, it_pipe_str[i].nb_byte_processed); } } } #endif Host_sof_action(); } // Host Wake-up has been received if (Is_host_hwup() && Is_host_hwup_interrupt_enabled()) { // CAUTION: HWUP can be cleared only when USB clock is active (not frozen)! //! @todo Implement this on the silicon version //Pll_start_auto(); // First Restart the PLL for USB operation //Wait_pll_ready(); // Make sure PLL is locked Usb_unfreeze_clock(); // Enable clock on USB interface (void)Is_usb_clock_frozen(); // Make sure USB interface clock is enabled Host_disable_hwup_interrupt(); // Wake-up interrupt should be disabled as host is now awoken! Host_ack_hwup(); // Clear HWUP interrupt flag Usb_send_event(EVT_HOST_HWUP); // Send software event Host_hwup_action(); // Map custom action } #if USB_HOST_PIPE_INTERRUPT_TRANSFER == ENABLE // Host pipe interrupts while ((i = Host_get_interrupt_pipe_number()) < MAX_PEP_NB) usb_pipe_interrupt(i); #endif } #endif // End HOST FEATURE MODE #ifdef FREERTOS_USED return task_woken; #endif }
ISR(usb_general_interrupt, AVR32_USBB_IRQ_GROUP, USB_INT_LEVEL) #endif { #ifdef FREERTOS_USED portBASE_TYPE task_woken = pdFALSE; #endif uint8_t i; /* avoid Cppcheck Warning */ UNUSED(i); // ---------- DEVICE/HOST events management ------------------------------------ #if USB_DEVICE_FEATURE == true && USB_HOST_FEATURE == true // ID pin change detection if (Is_usb_id_transition() && Is_usb_id_interrupt_enabled()) { g_usb_mode = (Is_usb_id_device()) ? USB_MODE_DEVICE : USB_MODE_HOST; Usb_ack_id_transition(); if (g_usb_mode != g_old_usb_mode) // Basic debounce { // Previously in device mode, check if disconnection was detected if (g_old_usb_mode == USB_MODE_DEVICE) { if (usb_connected) { // Device mode diconnection actions usb_connected = false; usb_configuration_nb = 0; Usb_vbus_off_action(); } } // Previously in host mode, check if disconnection was detected else if (Is_host_attached()) { // Host mode diconnection actions device_state = DEVICE_UNATTACHED; Host_device_disconnection_action(); } LOG_STR(log_pin_id_changed); Usb_send_event((Is_usb_device()) ? EVT_USB_DEVICE_FUNCTION : EVT_USB_HOST_FUNCTION); Usb_id_transition_action(); //! @todo ID pin hot state change!!! // Preliminary management: HARDWARE RESET!!! #if ID_PIN_CHANGE_GENERATE_RESET == ENABLE // Hot ID transition generates CPU reset Usb_disable(); Usb_disable_otg_pad(); #ifdef FREERTOS_USED // Release the semaphore in order to start a new device/host task taskENTER_CRITICAL(); xSemaphoreGiveFromISR(usb_tsk_semphr, &task_woken); taskEXIT_CRITICAL(); #else #if defined(CPU_RESET_CALLBACK) CPU_RESET_CALLBACK(); #endif Reset_CPU(); #endif #endif g_old_usb_mode = g_usb_mode; // Store current USB mode, for mode change detection } } #endif // End DEVICE/HOST FEATURE MODE // ---------- DEVICE events management ----------------------------------------- #if USB_DEVICE_FEATURE == true #if USB_HOST_FEATURE == true // If both device and host features are enabled, check if device mode is engaged // (accessing the USB registers of a non-engaged mode, even with load operations, // may corrupt USB FIFO data). if (Is_usb_device()) #endif { // VBus state detection if (Is_usb_vbus_transition() && Is_usb_vbus_interrupt_enabled()) { Usb_ack_vbus_transition(); if (Is_usb_vbus_high()) { usb_start_device(); Usb_send_event(EVT_USB_POWERED); Usb_vbus_on_action(); } else { Usb_unfreeze_clock(); Usb_detach(); usb_connected = false; usb_configuration_nb = 0; Usb_send_event(EVT_USB_UNPOWERED); Usb_vbus_off_action(); #ifdef FREERTOS_USED // Release the semaphore in order to start a new device/host task taskENTER_CRITICAL(); xSemaphoreGiveFromISR(usb_tsk_semphr, &task_woken); taskEXIT_CRITICAL(); #endif } } // Device Start-of-Frame received if (Is_usb_sof() && Is_usb_sof_interrupt_enabled()) { Usb_ack_sof(); Usb_sof_action(); } // Device Suspend event (no more USB activity detected) if (Is_usb_suspend() && Is_usb_suspend_interrupt_enabled()) { Usb_ack_suspend(); Usb_enable_wake_up_interrupt(); (void)Is_usb_wake_up_interrupt_enabled(); Usb_freeze_clock(); Usb_send_event(EVT_USB_SUSPEND); Usb_suspend_action(); } // Wake-up event (USB activity detected): Used to resume if (Is_usb_wake_up() && Is_usb_wake_up_interrupt_enabled()) { Usb_unfreeze_clock(); (void)Is_usb_clock_frozen(); Usb_ack_wake_up(); Usb_disable_wake_up_interrupt(); Usb_wake_up_action(); Usb_send_event(EVT_USB_WAKE_UP); } // Resume state bus detection if (Is_usb_resume() && Is_usb_resume_interrupt_enabled()) { Usb_disable_wake_up_interrupt(); Usb_ack_resume(); Usb_disable_resume_interrupt(); Usb_resume_action(); Usb_send_event(EVT_USB_RESUME); } // USB bus reset detection if (Is_usb_reset() && Is_usb_reset_interrupt_enabled()) { Usb_ack_reset(); usb_init_device(); Usb_reset_action(); Usb_send_event(EVT_USB_RESET); } } #endif // End DEVICE FEATURE MODE // ---------- HOST events management ------------------------------------------- #if USB_HOST_FEATURE == true #if USB_DEVICE_FEATURE == true // If both device and host features are enabled, check if host mode is engaged // (accessing the USB registers of a non-engaged mode, even with load operations, // may corrupt USB FIFO data). else #endif { // The device has been disconnected if (Is_host_device_disconnection() && Is_host_device_disconnection_interrupt_enabled()) { host_disable_all_pipes(); Host_ack_device_disconnection(); #if USB_HOST_PIPE_INTERRUPT_TRANSFER == ENABLE reset_it_pipe_str(); #endif #ifdef HOST_VBUS_LOW_TIMEOUT cpu_set_timeout(HOST_VBUS_LOW_TIMEOUT, &timer_vbus_low); device_state = DEVICE_VBUS_LOW; #else device_state = DEVICE_UNATTACHED; #endif LOG_STR(log_device_disconnected); Usb_send_event(EVT_HOST_DISCONNECTION); Host_device_disconnection_action(); #ifdef FREERTOS_USED // Release the semaphore in order to start a new device/host task taskENTER_CRITICAL(); xSemaphoreGiveFromISR(usb_tsk_semphr, &task_woken); taskEXIT_CRITICAL(); #endif } // Device connection if (Is_host_device_connection() && Is_host_device_connection_interrupt_enabled()) { Host_ack_device_connection(); host_disable_all_pipes(); Usb_send_event(EVT_HOST_CONNECTION); Host_device_connection_action(); } // Host Start-of-Frame has been sent if (Is_host_sof() && Is_host_sof_interrupt_enabled()) { Host_ack_sof(); Usb_send_event(EVT_HOST_SOF); private_sof_counter++; // Delay time-out management for interrupt tranfer mode in host mode #if USB_HOST_PIPE_INTERRUPT_TRANSFER == ENABLE && TIMEOUT_DELAY_ENABLE == ENABLE if (private_sof_counter >= 250) // Count 250 ms (SOF @ 1 ms) { private_sof_counter = 0; for (i = 0; i < MAX_PEP_NB; i++) { if (it_pipe_str[i].enable && ++it_pipe_str[i].timeout > TIMEOUT_DELAY && Host_get_pipe_type(i) != TYPE_INTERRUPT) { it_pipe_str[i].enable = false; it_pipe_str[i].status = PIPE_DELAY_TIMEOUT; Host_reset_pipe(i); if (!is_any_interrupt_pipe_active() && !g_sav_int_sof_enable) // If no more transfer is armed { Host_disable_sof_interrupt(); } it_pipe_str[i].handler(PIPE_DELAY_TIMEOUT, it_pipe_str[i].nb_byte_processed); } } } #endif Host_sof_action(); } // Host Wake-up has been received if (Is_host_hwup() && Is_host_hwup_interrupt_enabled()) { // CAUTION: HWUP can be cleared only when USB clock is active (not frozen)! //! @todo Implement this on the silicon version //Pll_start_auto(); // First Restart the PLL for USB operation //Wait_pll_ready(); // Make sure PLL is locked Usb_unfreeze_clock(); // Enable clock on USB interface (void)Is_usb_clock_frozen(); // Make sure USB interface clock is enabled Host_disable_hwup_interrupt(); // Wake-up interrupt should be disabled as host is now awoken! Host_ack_hwup(); // Clear HWUP interrupt flag Usb_send_event(EVT_HOST_HWUP); // Send software event Host_hwup_action(); // Map custom action } Host_int_action(); while ((i = Host_get_interrupt_pipe_number()) < MAX_PEP_NB) { if (Is_host_in_received(i) && Is_host_in_received_interrupt_enabled(i)) { Host_freeze_pipe(i); Host_disable_in_received_interrupt(i); } } #if defined(USB_HIGH_SPEED_SUPPORT) && USB_HIGH_SPEED_SUPPORT == true && \ defined(PIPE_AUDIO_IN) // Workaround - freeze the IN audio pipe if (Is_host_in_received(PIPE_AUDIO_IN)) { extern void workaround_freeze_iso_in(void); workaround_freeze_iso_in(); } #endif // USB_HIGH_SPEED_SUPPORT == true #if USB_HOST_PIPE_INTERRUPT_TRANSFER == ENABLE // Host pipe interrupts while ((i = Host_get_interrupt_pipe_number()) < MAX_PEP_NB) usb_pipe_interrupt(i); #endif } #endif // End HOST FEATURE MODE #ifdef FREERTOS_USED return task_woken; #endif }
__interrupt void usb_general_interrupt() #endif { #if (USB_HOST_PIPE_INTERRUPT_TRANSFER == ENABLE) U8 i; U8 save_pipe_nb; #endif // ---------- DEVICE events management ----------------------------------- #if (USB_DEVICE_FEATURE == ENABLED) // - Device start of frame received if (Is_usb_sof() && Is_sof_interrupt_enabled()) { Usb_ack_sof(); Usb_sof_action(); } #ifdef WA_USB_SUSPEND_PERTUBATION // - Device Suspend event (no more USB activity detected) if (Is_usb_suspend() && Is_suspend_interrupt_enabled()) { usb_suspended=TRUE; Usb_ack_wake_up(); // clear wake up to detect next event Usb_send_event(EVT_USB_SUSPEND); Usb_ack_suspend(); Usb_enable_wake_up_interrupt(); Usb_disable_resume_interrupt(); Usb_freeze_clock(); Stop_pll(); Usb_suspend_action(); } // - Wake up event (USB activity detected): Used to resume if (Is_usb_wake_up() && Is_wake_up_interrupt_enabled()) { if(Is_pll_ready()==FALSE) { Pll_start_auto(); Wait_pll_ready(); } Usb_unfreeze_clock(); Usb_ack_wake_up(); if(usb_suspended) { Usb_enable_resume_interrupt(); Usb_enable_reset_interrupt(); while(Is_usb_wake_up()) { Usb_ack_wake_up(); } usb_delay_ms(2); if(Is_usb_sof() || Is_usb_resume() || Is_usb_reset() ) { Usb_disable_wake_up_interrupt(); Usb_wake_up_action(); Usb_send_event(EVT_USB_WAKE_UP); Usb_enable_suspend_interrupt(); Usb_enable_resume_interrupt(); Usb_enable_reset_interrupt(); } else // Workarround to make the USB enter power down mode again (spurious transcient detected on the USB lines) { Usb_ack_wake_up(); // clear wake up to detect next event Usb_send_event(EVT_USB_SUSPEND); Usb_enable_wake_up_interrupt(); Usb_disable_resume_interrupt(); Usb_freeze_clock(); Stop_pll(); Usb_suspend_action(); } } } // - Resume state bus detection if (Is_usb_resume() && Is_resume_interrupt_enabled()) { usb_suspended = FALSE; Usb_disable_wake_up_interrupt(); Usb_ack_resume(); Usb_disable_resume_interrupt(); Usb_resume_action(); Usb_send_event(EVT_USB_RESUME); } #else // - Device Suspend event (no more USB activity detected) if (Is_usb_suspend() && Is_suspend_interrupt_enabled()) { // Remote wake-up handler if ((remote_wakeup_feature == ENABLED) && (usb_configuration_nb != 0)) { Usb_disable_suspend_interrupt(); Usb_ack_wake_up(); Usb_enable_wake_up_interrupt(); Stop_pll(); Usb_freeze_clock(); Usb_suspend_action(); // After that user can execute "Usb_initiate_remote_wake_up()" to initiate a remote wake-up // Note that the suspend interrupt flag SUSPI must still be set to enable upstream resume // So the SUSPE enable bit must be cleared to avoid redundant interrupt // **************** // Please note also that is Vbus is lost during an upstream resume (Host disconnection), // the RMWKUP bit (used to initiate remote wake up and that is normally cleared by hardware when sent) // remains set after the event, so that a good way to handle this feature is : // Usb_unfreeze_clock(); // Usb_initiate_remote_wake_up(); // while (Is_usb_pending_remote_wake_up()) // { // if (Is_usb_vbus_low()) // { // // Emergency action (reset macro, etc.) if Vbus lost during resuming // break; // } // } // Usb_ack_remote_wake_up_start(); // **************** } else { // No remote wake-up supported Usb_ack_wake_up(); // clear wake up to detect next event Usb_send_event(EVT_USB_SUSPEND); Usb_ack_suspend(); // must be executed last (after Usb_suspend_action()) to allow upstream resume Usb_enable_wake_up_interrupt(); Usb_freeze_clock(); Stop_pll(); Usb_suspend_action(); } } // - Wake up event (USB activity detected): Used to resume if (Is_usb_wake_up() && Is_wake_up_interrupt_enabled()) { if(Is_pll_ready()==FALSE) { Pll_start_auto(); Wait_pll_ready(); } Usb_unfreeze_clock(); Usb_ack_wake_up(); Usb_disable_wake_up_interrupt(); Usb_wake_up_action(); Usb_send_event(EVT_USB_WAKE_UP); Usb_enable_suspend_interrupt(); } // - Resume state bus detection if (Is_usb_resume() && Is_resume_interrupt_enabled()) { Usb_disable_wake_up_interrupt(); Usb_ack_resume(); Usb_disable_resume_interrupt(); Usb_resume_action(); Usb_send_event(EVT_USB_RESUME); } #endif // - USB bus reset detection if (Is_usb_reset()&& Is_reset_interrupt_enabled()) { Usb_ack_reset(); usb_init_device(); Usb_reset_action(); Usb_send_event(EVT_USB_RESET); } #endif// End DEVICE FEATURE MODE // ---------- HOST events management ----------------------------------- #if (USB_HOST_FEATURE == ENABLED && USB_DEVICE_FEATURE == ENABLED) // - ID pin change detection if(Is_usb_id_transition()&&Is_usb_id_interrupt_enabled()) { if(Is_usb_id_device()) { g_usb_mode=USB_MODE_DEVICE;} else { g_usb_mode=USB_MODE_HOST;} Usb_ack_id_transition(); if( g_usb_mode != g_old_usb_mode) // Basic Debounce { if(Is_usb_id_device()) // Going to device mode { Usb_send_event(EVT_USB_DEVICE_FUNCTION); } else // Going to host mode { Usb_send_event(EVT_USB_HOST_FUNCTION); } Usb_id_transition_action(); LOG_STR_CODE(log_id_change); #if ( ID_PIN_CHANGE_GENERATE_RESET == ENABLE) // Hot ID transition generates wdt reset wdtdrv_enable(WDTO_16MS); while(1); #endif } } #endif #if (USB_HOST_FEATURE == ENABLED) // - The device has been disconnected if(Is_device_disconnection() && Is_host_device_disconnection_interrupt_enabled()) { host_disable_all_pipe(); Host_ack_device_disconnection(); device_state=DEVICE_DISCONNECTED; Usb_send_event(EVT_HOST_DISCONNECTION); init_usb_tree(); LOG_STR_CODE(log_device_disconnect); Host_device_disconnection_action(); } // - Device connection if(Is_device_connection() && Is_host_device_connection_interrupt_enabled()) { Host_ack_device_connection(); host_disable_all_pipe(); Host_device_connection_action(); } // - Host Start of frame has been sent if (Is_host_sof() && Is_host_sof_interrupt_enabled()) { Host_ack_sof(); Usb_send_event(EVT_HOST_SOF); private_sof_counter++; #if (USB_HUB_SUPPORT==ENABLE) hub_interrupt_sof++; #endif // delay timeout management for interrupt tranfer mode in host mode #if ((USB_HOST_PIPE_INTERRUPT_TRANSFER==ENABLE) && (TIMEOUT_DELAY_ENABLE==ENABLE)) if (private_sof_counter>=250) // Count 1/4 sec { private_sof_counter=0; for(i=0;i<MAX_EP_NB;i++) { if(it_pipe_str[i].enable==ENABLE) { save_pipe_nb=Host_get_selected_pipe(); Host_select_pipe(i); if((++it_pipe_str[i].timeout>TIMEOUT_DELAY) && (Host_get_pipe_type()!=TYPE_INTERRUPT)) { it_pipe_str[i].enable=DISABLE; it_pipe_str[i].status=PIPE_DELAY_TIMEOUT; Host_stop_pipe_interrupt(i); if (is_any_interrupt_pipe_active()==FALSE) // If no more transfer is armed { if (g_sav_int_sof_enable==FALSE) { Host_disable_sof_interrupt(); } } it_pipe_str[i].handle(PIPE_DELAY_TIMEOUT,it_pipe_str[i].nb_byte_processed); } Host_select_pipe(save_pipe_nb); } } } #endif // (USB_HOST_PIPE_INTERRUPT_TRANSFER==ENABLE) && (TIMEOUT_DELAY_ENABLE==ENABLE)) Host_sof_action(); } // - Host Wake-up has been received if (Is_host_hwup() && Is_host_hwup_interrupt_enabled()) { Host_disable_hwup_interrupt(); // Wake up interrupt should be disable host is now wake up ! // CAUTION HWUP can be cleared only when USB clock is active (not frozen)! Pll_start_auto(); // First Restart the PLL for USB operation Wait_pll_ready(); // Get sure pll is lock Usb_unfreeze_clock(); // Enable clock on USB interface Host_ack_hwup(); // Clear HWUP interrupt flag Usb_send_event(EVT_HOST_HWUP); // Send software event Host_hwup_action(); // Map custom action } #endif // End HOST FEATURE MODE }
//! This function is the generic control pipe management function. //! This function is used to send and receive control requests over control pipe. //! //! @todo Fix all time-out errors and disconnections in active wait loop. //! //! @param data_pointer void *: Pointer to data to transfer //! //! @return Status_t: Status //! //! @note This function uses the usb_request global structure. Hence, this //! structure should be filled before calling this function. //! Status_t host_transfer_control(void *data_pointer) { int status = CONTROL_GOOD; bool sav_int_sof_enable; bool sav_glob_int_en; uint16_t data_length; uint8_t c; Usb_ack_event(EVT_HOST_SOF); sav_int_sof_enable = Is_host_sof_interrupt_enabled(); Host_enable_sof_interrupt(); // SOF software detection is in interrupt subroutine while (!Is_usb_event(EVT_HOST_SOF)) // Wait 1 SOF { #if defined(Host_wait_action) Host_wait_action(); #endif if (Is_host_emergency_exit()) { Host_freeze_pipe(P_CONTROL); Host_reset_pipe(P_CONTROL); status = CONTROL_TIMEOUT; goto host_transfer_control_end; } } Host_configure_pipe_token(P_CONTROL, TOKEN_SETUP); Host_ack_setup_ready(); Host_unfreeze_pipe(P_CONTROL); // Build and send the setup request fields Host_reset_pipe_fifo_access(P_CONTROL); Host_write_pipe_data(P_CONTROL, 8, usb_request.bmRequestType); Host_write_pipe_data(P_CONTROL, 8, usb_request.bRequest); Host_write_pipe_data(P_CONTROL, 16, usb_format_mcu_to_usb_data(16, usb_request.wValue)); Host_write_pipe_data(P_CONTROL, 16, usb_format_mcu_to_usb_data(16, usb_request.wIndex)); Host_write_pipe_data(P_CONTROL, 16, usb_format_mcu_to_usb_data(16, usb_request.wLength)); Host_send_setup(); while (!Is_host_setup_ready()) // Wait for SETUP ack { #if defined(Host_wait_action) Host_wait_action(); #endif if (Is_host_emergency_exit()) { Host_freeze_pipe(P_CONTROL); Host_reset_pipe(P_CONTROL); status = CONTROL_TIMEOUT; goto host_transfer_control_end; } if (Is_host_pipe_error(P_CONTROL)) // Any error? { c = Host_error_status(P_CONTROL); Host_ack_all_errors(P_CONTROL); status = c; // Send error status goto host_transfer_control_end; } } // Setup token sent; now send IN or OUT token // Before just wait 1 SOF Usb_ack_event(EVT_HOST_SOF); Host_freeze_pipe(P_CONTROL); data_length = usb_request.wLength; while (!Is_usb_event(EVT_HOST_SOF)) // Wait 1 SOF { #if defined(Host_wait_action) Host_wait_action(); #endif if (Is_host_emergency_exit()) { Host_freeze_pipe(P_CONTROL); Host_reset_pipe(P_CONTROL); status = CONTROL_TIMEOUT; goto host_transfer_control_end; } } // IN request management --------------------------------------------- if (usb_request.bmRequestType & 0x80) // Data stage IN (bmRequestType.D7 == 1) { Host_disable_continuous_in_mode(P_CONTROL); Host_configure_pipe_token(P_CONTROL, TOKEN_IN); Host_ack_control_in_received_free(); while (data_length) { Host_unfreeze_pipe(P_CONTROL); private_sof_counter = 0; // Reset the counter in SOF detection subroutine while (!Is_host_control_in_received()) { #if defined(Host_wait_action) Host_wait_action(); #endif if (Is_host_emergency_exit()) { Host_freeze_pipe(P_CONTROL); Host_reset_pipe(P_CONTROL); status = CONTROL_TIMEOUT; goto host_transfer_control_end; } if (Is_host_pipe_error(P_CONTROL)) // Any error? { c = Host_error_status(P_CONTROL); Host_ack_all_errors(P_CONTROL); status = c; // Send error status goto host_transfer_control_end; } if (Is_host_stall(P_CONTROL)) { Host_ack_stall(P_CONTROL); status = CONTROL_STALL; goto host_transfer_control_end; } #if TIMEOUT_DELAY_ENABLE == ENABLE if (1000 < host_get_timeout()) // Count 1s { Host_freeze_pipe(P_CONTROL); Host_reset_pipe(P_CONTROL); status = CONTROL_TIMEOUT; goto host_transfer_control_end; } #endif } Host_reset_pipe_fifo_access(P_CONTROL); c = Host_get_pipe_size(P_CONTROL) - Host_byte_count(P_CONTROL); data_length = host_read_p_rxpacket(P_CONTROL, data_pointer, data_length, &data_pointer); if (usb_request.incomplete_read || c) data_length = 0; Host_freeze_pipe(P_CONTROL); Host_ack_control_in_received_free(); // In low-speed mode, the USB IP may have not yet sent the ACK at this // point. The USB IP does not support a new start of transaction request // from the firmware if the ACK has not been sent. The only means of // making sure the ACK has been sent is to wait for the next Keep-Alive // before starting a new transaction. if (Is_usb_low_speed_mode()) { Usb_ack_event(EVT_HOST_SOF); if ((sav_glob_int_en = cpu_irq_is_enabled())) cpu_irq_disable(); Host_ack_sof(); (void)Is_host_sof_interrupt_enabled(); if (sav_glob_int_en) cpu_irq_enable(); while (!Is_usb_event(EVT_HOST_SOF)) // Wait for next Keep-Alive { if (Is_host_emergency_exit()) { Host_freeze_pipe(P_CONTROL); Host_reset_pipe(P_CONTROL); status = CONTROL_TIMEOUT; goto host_transfer_control_end; } } } } // End of IN data stage Host_configure_pipe_token(P_CONTROL, TOKEN_OUT); Host_ack_control_out_ready_send(); Host_unfreeze_pipe(P_CONTROL); #if TIMEOUT_DELAY_ENABLE == ENABLE private_sof_counter = 0; // Reset the counter in SOF detection subroutine #endif while (!Is_host_control_out_ready()) { #if defined(Host_wait_action) Host_wait_action(); #endif if (Is_host_emergency_exit()) { Host_freeze_pipe(P_CONTROL); Host_reset_pipe(P_CONTROL); status = CONTROL_TIMEOUT; goto host_transfer_control_end; } if (Is_host_pipe_error(P_CONTROL)) // Any error? { c = Host_error_status(P_CONTROL); Host_ack_all_errors(P_CONTROL); status = c; // Send error status goto host_transfer_control_end; } if (Is_host_stall(P_CONTROL)) { Host_ack_stall(P_CONTROL); status = CONTROL_STALL; goto host_transfer_control_end; } #if TIMEOUT_DELAY_ENABLE == ENABLE if (2000 < host_get_timeout()) // Count 2s { Host_freeze_pipe(P_CONTROL); Host_reset_pipe(P_CONTROL); status = CONTROL_TIMEOUT; goto host_transfer_control_end; } #endif } Host_ack_control_out_ready(); } // OUT request management -------------------------------------------- else // Data stage OUT (bmRequestType.D7 == 0) { Host_configure_pipe_token(P_CONTROL, TOKEN_OUT); Host_ack_control_out_ready(); while (data_length) { Host_unfreeze_pipe(P_CONTROL); Host_reset_pipe_fifo_access(P_CONTROL); data_length = host_write_p_txpacket(P_CONTROL, data_pointer, data_length, (const void **)&data_pointer); Host_send_control_out(); while (!Is_host_control_out_ready()) { #if defined(Host_wait_action) Host_wait_action(); #endif if (Is_host_emergency_exit()) { Host_freeze_pipe(P_CONTROL); Host_reset_pipe(P_CONTROL); status = CONTROL_TIMEOUT; goto host_transfer_control_end; } if (Is_host_pipe_error(P_CONTROL)) // Any error? { c = Host_error_status(P_CONTROL); Host_ack_all_errors(P_CONTROL); status = c; // Send error status goto host_transfer_control_end; } if (Is_host_stall(P_CONTROL)) { Host_ack_stall(P_CONTROL); status = CONTROL_STALL; goto host_transfer_control_end; } } Host_ack_control_out_ready(); } // End of OUT data stage Host_freeze_pipe(P_CONTROL); Host_configure_pipe_token(P_CONTROL, TOKEN_IN); Host_ack_control_in_received_free(); Host_unfreeze_pipe(P_CONTROL); #if TIMEOUT_DELAY_ENABLE == ENABLE private_sof_counter = 0; // Reset the counter in SOF detection subroutine #endif while (!Is_host_control_in_received()) { #if defined(Host_wait_action) Host_wait_action(); #endif if (Is_host_emergency_exit()) { Host_freeze_pipe(P_CONTROL); Host_reset_pipe(P_CONTROL); status = CONTROL_TIMEOUT; goto host_transfer_control_end; } if (Is_host_pipe_error(P_CONTROL)) // Any error? { c = Host_error_status(P_CONTROL); Host_ack_all_errors(P_CONTROL); status = c; // Send error status goto host_transfer_control_end; } if (Is_host_stall(P_CONTROL)) { Host_ack_stall(P_CONTROL); status = CONTROL_STALL; goto host_transfer_control_end; } #if TIMEOUT_DELAY_ENABLE == ENABLE if (2000 < host_get_timeout()) // Count 2s { Host_freeze_pipe(P_CONTROL); Host_reset_pipe(P_CONTROL); status = CONTROL_TIMEOUT; goto host_transfer_control_end; } #endif } Host_ack_control_in_received(); Host_freeze_pipe(P_CONTROL); Host_free_control_in(); } host_transfer_control_end: if (!sav_int_sof_enable) // Restore SOF interrupt enable { if ((sav_glob_int_en = cpu_irq_is_enabled())) cpu_irq_disable(); Host_disable_sof_interrupt(); (void)Is_host_sof_interrupt_enabled(); if (sav_glob_int_en) cpu_irq_enable(); } return status; }
//! //! @brief This function receives nb_data bytes pointed to by ptr_buf on the specified pipe. //! //! *nb_data is updated with the final number of data bytes received. //! //! @note This function activates the host SOF interrupt to detect time-outs. //! The initial enable state of this interrupt will be restored. //! //! @param pipe //! @param nb_data //! @param ptr_buf //! //! @return Status_t: Pipe status //! Status_t host_get_data(uint8_t pipe, uint16_t *nb_data, void *ptr_buf) { Status_t status = PIPE_GOOD; // Frame correctly received by default bool sav_int_sof_enable; bool sav_glob_int_en; uint8_t nak_timeout; uint16_t n, i; #if NAK_TIMEOUT_ENABLE == ENABLE uint16_t cpt_nak; #endif n = *nb_data; sav_int_sof_enable = Is_host_sof_interrupt_enabled(); Host_enable_sof_interrupt(); Host_enable_continuous_in_mode(pipe); Host_configure_pipe_token(pipe, TOKEN_IN); Host_ack_in_received(pipe); while (n) // While missing data... { Host_free_in(pipe); Host_unfreeze_pipe(pipe); private_sof_counter = 0; // Reset the counter in SOF detection subroutine nak_timeout = 0; #if NAK_TIMEOUT_ENABLE == ENABLE cpt_nak = 0; #endif while (!Is_host_in_received(pipe)) { if (Is_host_emergency_exit()) // Asynchronous disconnection or role exchange detected under interrupt { status = PIPE_DELAY_TIMEOUT; Host_reset_pipe(pipe); goto host_get_data_end; } #if TIMEOUT_DELAY_ENABLE == ENABLE if (private_sof_counter >= 250) // Time-out management { private_sof_counter = 0; // Done in host SOF interrupt if (nak_timeout++ >= TIMEOUT_DELAY) // Check for local time-out { status = PIPE_DELAY_TIMEOUT; Host_reset_pipe(pipe); goto host_get_data_end; } } #endif if (Is_host_pipe_error(pipe)) // Error management { status = Host_error_status(pipe); Host_ack_all_errors(pipe); goto host_get_data_end; } if (Is_host_stall(pipe)) // STALL management { status = PIPE_STALL; Host_reset_pipe(pipe); Host_ack_stall(pipe); goto host_get_data_end; } #if NAK_TIMEOUT_ENABLE == ENABLE if (Is_host_nak_received(pipe)) // NAK received { Host_ack_nak_received(pipe); if (cpt_nak++ > NAK_RECEIVE_TIMEOUT) { status = PIPE_NAK_TIMEOUT; Host_reset_pipe(pipe); goto host_get_data_end; } } #endif } Host_freeze_pipe(pipe); Host_reset_pipe_fifo_access(pipe); i = Host_get_pipe_size(pipe) - Host_byte_count(pipe); if (!ptr_buf) { if (Host_byte_count(pipe) > n) // More bytes received than expected { n = 0; //! @todo Error code management } else // Nb bytes received <= expected { n -= Host_byte_count(pipe); if (i) // Short packet { *nb_data -= n; n = 0; } } } else { n = host_read_p_rxpacket(pipe, ptr_buf, n, &ptr_buf); if (Host_byte_count(pipe)) // More bytes received than expected { //! @todo Error code management } else if (i) // Short packet with nb bytes received <= expected { *nb_data -= n; n = 0; } } Host_ack_in_received(pipe); // In low-speed mode, the USB IP may have not yet sent the ACK at this // point. The USB IP does not support a new start of transaction request // from the firmware if the ACK has not been sent. The only means of making // sure the ACK has been sent is to wait for the next Keep-Alive before // starting a new transaction. if (Is_usb_low_speed_mode()) { Usb_ack_event(EVT_HOST_SOF); sav_int_sof_enable = Is_host_sof_interrupt_enabled(); if ((sav_glob_int_en = cpu_irq_is_enabled())) cpu_irq_disable(); Host_ack_sof(); (void)Is_host_sof_interrupt_enabled(); if (sav_glob_int_en) cpu_irq_enable(); Host_enable_sof_interrupt(); while (!Is_usb_event(EVT_HOST_SOF)) // Wait for next Keep-Alive { if (Is_host_emergency_exit()) { status = PIPE_DELAY_TIMEOUT; Host_reset_pipe(pipe); goto host_get_data_end; } } if (!sav_int_sof_enable) // Restore SOF interrupt enable { if ((sav_glob_int_en = cpu_irq_is_enabled())) cpu_irq_disable(); Host_disable_sof_interrupt(); (void)Is_host_sof_interrupt_enabled(); if (sav_glob_int_en) cpu_irq_enable(); } } } host_get_data_end: Host_freeze_pipe(pipe); // Restore SOF interrupt enable state if (!sav_int_sof_enable) { if ((sav_glob_int_en = cpu_irq_is_enabled())) cpu_irq_disable(); Host_disable_sof_interrupt(); (void)Is_host_sof_interrupt_enabled(); if (sav_glob_int_en) cpu_irq_enable(); } // And return... return status; }
//! //! @brief This function sends nb_data bytes pointed to by ptr_buf on the specified pipe. //! //! @note This function activates the host SOF interrupt to detect time-outs. //! The initial enable state of this interrupt will be restored. //! //! @param pipe //! @param nb_data //! @param ptr_buf //! //! @return Status_t: Pipe status //! Status_t host_send_data(uint8_t pipe, uint16_t nb_data, const void *ptr_buf) { Status_t status = PIPE_GOOD; // Frame correctly sent by default bool sav_int_sof_enable; bool sav_glob_int_en; uint8_t nak_timeout; #if NAK_TIMEOUT_ENABLE == ENABLE uint16_t cpt_nak; #endif sav_int_sof_enable = Is_host_sof_interrupt_enabled(); // Save state of enable SOF interrupt Host_enable_sof_interrupt(); Host_configure_pipe_token(pipe, TOKEN_OUT); Host_ack_out_ready(pipe); Host_unfreeze_pipe(pipe); while (nb_data) // While there is something to send... { // Prepare data to be sent Host_reset_pipe_fifo_access(pipe); nb_data = host_write_p_txpacket(pipe, ptr_buf, nb_data, &ptr_buf); private_sof_counter = 0; // Reset the counter in SOF detection subroutine #if NAK_TIMEOUT_ENABLE == ENABLE cpt_nak = 0; #endif nak_timeout = 0; Host_ack_out_ready_send(pipe); while (!Is_host_out_ready(pipe)) { if (Is_host_emergency_exit()) // Async disconnection or role change detected under interrupt { status = PIPE_DELAY_TIMEOUT; Host_reset_pipe(pipe); goto host_send_data_end; } #if TIMEOUT_DELAY_ENABLE == ENABLE if (private_sof_counter >= 250) // Count 250 ms (250 SOF) { private_sof_counter = 0; if (nak_timeout++ >= TIMEOUT_DELAY) // Increment time-out and check for overflow { status = PIPE_DELAY_TIMEOUT; Host_reset_pipe(pipe); goto host_send_data_end; } } #endif if (Is_host_pipe_error(pipe)) // Error management { status = Host_error_status(pipe); Host_ack_all_errors(pipe); goto host_send_data_end; } if (Is_host_stall(pipe)) // STALL management { status = PIPE_STALL; Host_ack_stall(pipe); goto host_send_data_end; } #if NAK_TIMEOUT_ENABLE == ENABLE if (Is_host_nak_received(pipe)) // NAK received { Host_ack_nak_received(pipe); if (cpt_nak++ > NAK_SEND_TIMEOUT) { status = PIPE_NAK_TIMEOUT; Host_reset_pipe(pipe); goto host_send_data_end; } } #endif } // Here OUT sent Host_ack_out_ready(pipe); } while (Host_nb_busy_bank(pipe)); host_send_data_end: Host_freeze_pipe(pipe); // Restore SOF interrupt enable state if (!sav_int_sof_enable) { if ((sav_glob_int_en = cpu_irq_is_enabled())) cpu_irq_disable(); Host_disable_sof_interrupt(); (void)Is_host_sof_interrupt_enabled(); if (sav_glob_int_en) cpu_irq_enable(); } // And return... return status; }
void usb_host_task(void) #endif { #define DEVICE_DEFAULT_MAX_ERROR_COUNT 2 static uint8_t device_default_error_count; #ifdef HOST_VBUS_LOW_TIMEOUT extern t_cpu_time timer_vbus_low; #endif static bool sav_int_sof_enable; uint8_t pipe; #ifdef FREERTOS_USED portTickType xLastWakeTime; xLastWakeTime = xTaskGetTickCount(); while (true) { vTaskDelayUntil(&xLastWakeTime, configTSK_USB_HST_PERIOD); #endif // FREERTOS_USED switch (device_state) { #ifdef HOST_VBUS_LOW_TIMEOUT case DEVICE_VBUS_LOW: Usb_disable_vbus(); if (cpu_is_timeout(&timer_vbus_low)) usb_host_task_init(); break; #endif //------------------------------------------------------ // DEVICE_UNATTACHED state // // - Default init state // - Try to give device power supply // case DEVICE_UNATTACHED: device_default_error_count = 0; nb_interface_supported = 0; Host_clear_device_status(); // Reset device status Usb_clear_all_event(); // Clear all software events Host_disable_sof(); host_disable_all_pipes(); Usb_enable_vbus(); // Give at least device power supply! // If VBus OK, wait for device connection if (Is_usb_vbus_high()) device_state = DEVICE_ATTACHED; break; //------------------------------------------------------ // DEVICE_ATTACHED state // // - VBus is on // - Try to detect device connection // case DEVICE_ATTACHED: if (Is_host_device_connection() || Is_usb_event(EVT_HOST_CONNECTION) ) // Device pull-up detected { device_attached_retry: if( Is_usb_event(EVT_HOST_CONNECTION) ) { Usb_ack_event(EVT_HOST_CONNECTION); } Usb_ack_bconnection_error_interrupt(); Usb_ack_vbus_error_interrupt(); Host_ack_device_connection(); Host_clear_device_status(); // Reset device status cpu_irq_disable(); Host_disable_device_disconnection_interrupt(); Host_send_reset(); // First USB reset (void)Is_host_sending_reset(); cpu_irq_enable(); Usb_ack_event(EVT_HOST_SOF); // Active wait for end of reset send while (Is_host_sending_reset()) { // The USB macro does not signal the end of reset when a disconnection occurs if (Is_host_device_disconnection()) { // Stop sending USB reset Host_stop_sending_reset(); } } Host_ack_reset_sent(); Host_enable_sof(); // Start SOF generation Host_enable_sof_interrupt(); // SOF will be detected under interrupt if (!Is_host_device_disconnection()) { // Workaround for some buggy devices with powerless pull-up // usually low-speed where data line rises slowly and can be interpreted as disconnection for (sof_cnt = 0; sof_cnt < 0xFFFF; sof_cnt++) // Basic time-out counter { // If we detect SOF, device is still alive and connected, just clear false disconnect flag if (Is_usb_event(EVT_HOST_SOF) && Is_host_device_disconnection()) { Host_ack_device_connection(); Host_ack_device_disconnection(); break; } } } Host_enable_device_disconnection_interrupt(); sof_cnt = 0; while (sof_cnt < 100) // Wait 100 ms after USB reset { if (Is_usb_event(EVT_HOST_SOF)) Usb_ack_event(EVT_HOST_SOF), sof_cnt++; // Count SOFs if (Is_host_emergency_exit() || Is_usb_bconnection_error_interrupt()) goto device_attached_error; } device_state = DEVICE_POWERED; LOG_STR(log_device_connected); Host_device_connection_action(); sof_cnt = 0; } device_attached_error: // Device connection error, or VBus pb -> Retry the connection process from the beginning if (Is_usb_bconnection_error_interrupt() || Is_usb_vbus_error_interrupt() || Is_usb_vbus_low()) { if (device_state != DEVICE_VBUS_LOW) device_state = DEVICE_UNATTACHED; Usb_ack_bconnection_error_interrupt(); Usb_ack_vbus_error_interrupt(); Host_disable_sof(); } break; //------------------------------------------------------ // DEVICE_POWERED state // // - Device connection (attach) has been detected, // - Wait 100 ms and configure default control pipe // case DEVICE_POWERED: if (Is_usb_event(EVT_HOST_SOF)) { Usb_ack_event(EVT_HOST_SOF); if (sof_cnt++ >= 100) // Wait 100 ms { Host_enable_pipe(P_CONTROL); (void)Host_configure_pipe(P_CONTROL, 0, EP_CONTROL, TYPE_CONTROL, TOKEN_SETUP, 8, SINGLE_BANK); device_state = DEVICE_DEFAULT; } } break; //------------------------------------------------------ // DEVICE_DEFAULT state // // - Get device descriptor // - Reconfigure control pipe according to device control endpoint // - Assign device address // case DEVICE_DEFAULT: // Get first device descriptor if (host_get_device_descriptor_incomplete() == CONTROL_GOOD) { sof_cnt = 0; while (sof_cnt < 20) // Wait 20 ms before USB reset (special buggy devices...) { if (Is_usb_event(EVT_HOST_SOF)) Usb_ack_event(EVT_HOST_SOF), sof_cnt++; if (Is_host_emergency_exit() || Is_usb_bconnection_error_interrupt()) break; } cpu_irq_disable(); Host_disable_device_disconnection_interrupt(); Host_send_reset(); // First USB reset (void)Is_host_sending_reset(); cpu_irq_enable(); Usb_ack_event(EVT_HOST_SOF); // Active wait for end of reset send while (Is_host_sending_reset()) { // The USB macro does not signal the end of reset when a disconnection occurs if (Is_host_device_disconnection()) { // Stop sending USB reset Host_stop_sending_reset(); } } Host_ack_reset_sent(); if (!Is_host_device_disconnection()) { // Workaround for some buggy devices with powerless pull-up // usually low-speed where data line rises slowly and can be interpreted as disconnection for (sof_cnt = 0; sof_cnt < 0xFFFF; sof_cnt++) // Basic time-out counter { // If we detect SOF, device is still alive and connected, just clear false disconnect flag if (Is_usb_event(EVT_HOST_SOF) && Is_host_device_disconnection()) { Host_ack_device_connection(); Host_ack_device_disconnection(); break; } } } Host_enable_device_disconnection_interrupt(); sof_cnt = 0; while (sof_cnt < 200) // Wait 200 ms after USB reset { if (Is_usb_event(EVT_HOST_SOF)) Usb_ack_event(EVT_HOST_SOF), sof_cnt++; if (Is_host_emergency_exit() || Is_usb_bconnection_error_interrupt()) break; } Host_disable_pipe(P_CONTROL); Host_unallocate_memory(P_CONTROL); Host_enable_pipe(P_CONTROL); // Reconfigure the control pipe according to the device control endpoint (void)Host_configure_pipe(P_CONTROL, 0, EP_CONTROL, TYPE_CONTROL, TOKEN_SETUP, data_stage[OFFSET_FIELD_MAXPACKETSIZE], SINGLE_BANK); // Give an absolute device address if (host_set_address(DEVICE_ADDRESS) == CONTROL_GOOD) { for (pipe = 0; pipe < MAX_PEP_NB; pipe++) Host_configure_address(pipe, DEVICE_ADDRESS); device_state = DEVICE_ADDRESSED; } else if (device_state != DEVICE_VBUS_LOW) device_state = DEVICE_ERROR; } else { if (device_state != DEVICE_VBUS_LOW) { if (++device_default_error_count > DEVICE_DEFAULT_MAX_ERROR_COUNT) device_state = DEVICE_ERROR; else { Host_disable_sof(); Host_disable_pipe(P_CONTROL); Host_unallocate_memory(P_CONTROL); device_state = DEVICE_ATTACHED; goto device_attached_retry; } } Usb_ack_bconnection_error_interrupt(); Usb_ack_vbus_error_interrupt(); Host_disable_sof(); } break; //------------------------------------------------------ // DEVICE_ADDRESSED state // // - Check if VID PID is in supported list // case DEVICE_ADDRESSED: if (host_get_device_descriptor() == CONTROL_GOOD) { // Detect if the device connected belongs to the supported devices table if (host_check_VID_PID()) { Host_set_device_supported(); Host_device_supported_action(); device_state = DEVICE_CONFIGURED; } else { #if HOST_STRICT_VID_PID_TABLE == ENABLE device_state = DEVICE_ERROR; LOG_STR(log_unsupported_device); #else device_state = DEVICE_CONFIGURED; #endif Host_device_not_supported_action(); } } else if (device_state != DEVICE_VBUS_LOW) device_state = DEVICE_ERROR; // Can not get device descriptor break; //------------------------------------------------------ // DEVICE_CONFIGURED state // // - Configure pipes for the supported interface // - Send Set_configuration() request // - Go to full operating mode (device ready) // case DEVICE_CONFIGURED: { uint8_t configuration_index = 0; if (host_get_configuration_descriptor(configuration_index) == CONTROL_GOOD) { if (host_check_class()) // Class support OK? { #if HOST_AUTO_CFG_ENDPOINT == DISABLE User_configure_endpoint(); // User call here instead of autoconfig Host_set_configured(); // Assumes config is OK with user config #endif if (Is_host_configured()) { if (host_set_configuration(data_stage[OFFSET_FIELD_CONFIGURATION_NB]) == CONTROL_GOOD) // Send Set_configuration { // Device and host are now fully configured // go to DEVICE_READY normal operation device_state = DEVICE_READY; // Monitor device disconnection under interrupt Host_enable_device_disconnection_interrupt(); // If user host application requires SOF interrupt event // Keep SOF interrupt enabled, otherwise disable this interrupt #if HOST_CONTINUOUS_SOF_INTERRUPT == DISABLE cpu_irq_disable(); Host_disable_sof_interrupt(); (void)Is_host_sof_interrupt_enabled(); cpu_irq_enable(); #endif Host_new_device_connection_action(); cpu_irq_enable(); LOG_STR(log_device_enumerated); } else if (device_state != DEVICE_VBUS_LOW) device_state = DEVICE_ERROR; // Problem during Set_configuration request... } } else // Device class not supported... { device_state = DEVICE_UNSUPPORTED; LOG_STR(log_unsupported_device); Host_device_class_not_supported_action(); } } else if (device_state != DEVICE_VBUS_LOW) device_state = DEVICE_ERROR; // Can not get configuration descriptors... } break; //------------------------------------------------------ // DEVICE_READY state // // - Full standard operating mode // - Nothing to do... // case DEVICE_READY: // Host full standard operating mode! break; //------------------------------------------------------ // DEVICE_UNSUPPORTED state // case DEVICE_UNSUPPORTED: break; //------------------------------------------------------ // DEVICE_ERROR state // // - Error state // - Do custom action call (probably go to default mode...) // case DEVICE_ERROR: //! @todo #if HOST_ERROR_RESTART == ENABLE device_state = DEVICE_UNATTACHED; #endif Host_device_error_action(); break; //------------------------------------------------------ // DEVICE_SUSPENDED state // // - Host application request to suspend the device activity // - State machine comes here thanks to Host_request_suspend() // case DEVICE_SUSPENDED: if (Is_device_supports_remote_wakeup()) // If the connected device supports remote wake-up { host_set_feature_remote_wakeup(); // Enable this feature... } LOG_STR(log_usb_suspended); sav_int_sof_enable = Is_host_sof_interrupt_enabled(); //Save current SOF interrupt enable state cpu_irq_disable(); Host_disable_sof_interrupt(); (void)Is_host_sof_interrupt_enabled(); cpu_irq_enable(); Host_ack_sof(); Host_disable_sof(); // Stop SOF generation, this generates the suspend state Host_ack_hwup(); Host_enable_hwup_interrupt(); // Enable host wake-up interrupt // (this is the unique USB interrupt able to wake up the CPU core from power-down mode) (void)Is_host_hwup_interrupt_enabled(); // Make sure host wake-up interrupt is enabled Usb_freeze_clock(); //! @todo Implement this on the silicon version //Stop_pll(); Host_suspend_action(); // Custom action here! (e.g. go to power-save mode...) device_state = DEVICE_WAIT_RESUME; // Wait for device resume event break; //------------------------------------------------------ // DEVICE_WAIT_RESUME state // // Wait in this state till: // - the host receives an upstream resume from the device // - or the host software request the device to resume // case DEVICE_WAIT_RESUME: if (Is_usb_event(EVT_HOST_HWUP) || Is_host_request_resume()) // Remote wake-up has been detected // or local resume request has been received { if (Is_host_request_resume()) // Not a remote wake-up, but a host application request { // CAUTION: HWUP can be cleared only when USB clock is active //! @todo Implement this on the silicon version //Pll_start_auto(); // First Restart the PLL for USB operation //Wait_pll_ready(); // Make sure PLL is locked Usb_unfreeze_clock(); // Enable clock on USB interface (void)Is_usb_clock_frozen(); // Make sure USB interface clock is enabled cpu_irq_disable(); Host_disable_hwup_interrupt(); // Wake-up interrupt should be disabled as host is now awoken! (void)Is_host_hwup_interrupt_enabled(); cpu_irq_enable(); Host_ack_hwup(); // Clear HWUP interrupt flag } Host_enable_sof(); Host_send_resume(); // Send downstream resume while (!Is_host_down_stream_resume()); // Wait for downstream resume sent Host_ack_remote_wakeup(); // Ack remote wake-up reception Host_ack_request_resume(); // Ack software request Host_ack_down_stream_resume(); // Ack downstream resume sent Usb_ack_event(EVT_HOST_HWUP); // Ack software event if (sav_int_sof_enable) Host_enable_sof_interrupt(); // Restore SOF interrupt enable state before suspend device_state = DEVICE_READY; // Come back to full operating mode LOG_STR(log_usb_resumed); } break; //------------------------------------------------------ // default state // // - Default case: ERROR // - Go to DEVICE_UNATTACHED state // default: device_state = DEVICE_UNATTACHED; break; } #ifdef FREERTOS_USED } #endif }
/** * @brief This function receives nb_data pointed with *buf with the pipe number specified * * The nb_data parameter is passed as a U16 pointer, thus the data pointed by this pointer * is updated with the final number of data byte received. * * @param pipe * @param nb_data * @param buf * * @return status */ U8 host_get_data(U8 pipe, U16 *nb_data, U8 *buf) { U8 status=PIPE_GOOD; U8 sav_int_sof_enable; U8 nak_timeout; U16 n,i; U16 cpt_nak; #if (USER_PERIODIC_PIPE==ENABLE) freeze_user_periodic_pipe(); #endif n=*nb_data; *nb_data=0; sav_int_sof_enable=Is_host_sof_interrupt_enabled(); Host_enable_sof_interrupt(); Host_select_pipe(pipe); Host_continuous_in_mode(); Host_set_token_in(); Host_ack_in_received(); while (n) // While missing data... { Host_unfreeze_pipe(); Host_send_in(); private_sof_counter=0; // Reset the counter in SOF detection sub-routine nak_timeout=0; cpt_nak=0; while (!Is_host_in_received()) { if (Is_host_emergency_exit()) // Async disconnection or role change detected under interrupt { status=PIPE_DELAY_TIMEOUT; Host_reset_pipe(pipe); goto host_get_data_end; } #if (TIMEOUT_DELAY_ENABLE==ENABLE) if (private_sof_counter>=250) // Timeout management { private_sof_counter=0; // Done in host SOF interrupt if (nak_timeout++>=TIMEOUT_DELAY)// Check for local timeout { status=PIPE_DELAY_TIMEOUT; Host_reset_pipe(pipe); goto host_get_data_end; } } #endif if(Is_host_pipe_error()) // Error management { status = Host_error_status(); Host_ack_all_errors(); goto host_get_data_end; } if(Is_host_stall()) // STALL management { if( Is_host_in_received() ) break; status =PIPE_STALL; Host_reset_pipe(pipe); Host_ack_stall(); goto host_get_data_end; } #if (NAK_TIMEOUT_ENABLE==ENABLE) if(Is_host_nak_received()) //NAK received { Host_ack_nak_received(); if (cpt_nak++>NAK_RECEIVE_TIMEOUT) { status = PIPE_NAK_TIMEOUT; Host_reset_pipe(pipe); goto host_get_data_end; } } #endif } status=PIPE_GOOD; Host_freeze_pipe(); if (Host_byte_counter()<=n) { if ((Host_byte_counter() < n)&&(Host_byte_counter()<Host_get_pipe_length())) { n=0;} else { n-=Host_byte_counter();} (*nb_data)+=Host_byte_counter(); // Update nb of byte received if( NULL != buf ) { for (i=Host_byte_counter();i;i--) { *buf=Host_read_byte(); buf++;} } } else // more bytes received than expected { // TODO error code management *nb_data+=n; if( NULL != buf ) { for (i=n;i;i--) // Byte number limited to the initial request (limit tab over pb) { *buf=Host_read_byte(); buf++; } } n=0; } Host_ack_in_received(); } Host_freeze_pipe(); host_get_data_end: if (sav_int_sof_enable==FALSE) { Host_disable_sof_interrupt(); } #if (USER_PERIODIC_PIPE==ENABLE) unfreeze_user_periodic_pipe(); #endif return ((U8)status); }
/** * @brief This function send nb_data pointed with *buf with the pipe number specified * * @note This function will activate the host sof interrupt to detect timeout. The * interrupt enable sof will be restore. * * @param pipe * @param nb_data * @param buf * * @return status */ U8 host_send_data(U8 pipe, U16 nb_data, U8 *buf) { U8 c; U8 status=PIPE_GOOD; U8 sav_int_sof_enable; U8 nak_timeout; U16 cpt_nak; U8 nb_data_loaded; U8 cpt_err_timeout=0; #if (USER_PERIODIC_PIPE==ENABLE) freeze_user_periodic_pipe(); #endif sav_int_sof_enable=Is_host_sof_interrupt_enabled(); // Save state of enable sof interrupt Host_enable_sof_interrupt(); Host_select_pipe(pipe); Host_set_token_out(); Host_ack_out_sent(); Host_unfreeze_pipe(); while (nb_data != 0) // While there is something to send... { // Prepare data to be sent c = Host_get_pipe_length(); if ( (U16)c > nb_data) { nb_data_loaded = (U8)nb_data; c = nb_data; } else { nb_data_loaded = c; } while (c!=0) // Load Pipe buffer { Host_write_byte(*buf++); c--; } private_sof_counter=0; // Reset the counter in SOF detection sub-routine cpt_nak=0; nak_timeout=0; Host_ack_out_sent(); Host_send_out(); while (!Is_host_out_sent()) { if (Is_host_emergency_exit())// Async disconnection or role change detected under interrupt { status=PIPE_DELAY_TIMEOUT; Host_reset_pipe(pipe); goto host_send_data_end; } #if (TIMEOUT_DELAY_ENABLE==ENABLE) if (private_sof_counter>=250) // Count 250ms (250sof) { private_sof_counter=0; if (nak_timeout++>=TIMEOUT_DELAY) // Inc timeout and check for overflow { status=PIPE_DELAY_TIMEOUT; Host_reset_pipe(pipe); goto host_send_data_end; } } #endif if (Is_host_pipe_error()) // Any error ? { status = Host_error_status(); Host_ack_all_errors(); if(status == PIPE_TIMEOUT) { if(cpt_err_timeout++>100) { goto host_send_data_end; } else { c=0; while(c<2) // wait 2 ms { if (Is_usb_event(EVT_HOST_SOF)) { Usb_ack_event(EVT_HOST_SOF); c++; } if (Is_host_emergency_exit() ) {break;} } Host_unfreeze_pipe(); } } } if (Is_host_stall()) // Stall management { status =PIPE_STALL; Host_ack_stall(); goto host_send_data_end; } #if (NAK_TIMEOUT_ENABLE==ENABLE) if(Is_host_nak_received()) //NAK received { Host_ack_nak_received(); if (cpt_nak++>NAK_SEND_TIMEOUT) { status = PIPE_NAK_TIMEOUT; Host_reset_pipe(pipe); goto host_send_data_end; } } #endif } // Here OUT sent nb_data -= nb_data_loaded; status=PIPE_GOOD; // Frame correctly sent Host_ack_out_sent(); } while(0!=Host_number_of_busy_bank()); host_send_data_end: Host_freeze_pipe(); // Restore sof interrupt enable state if (sav_int_sof_enable==FALSE) {Host_disable_sof_interrupt();} #if (USER_PERIODIC_PIPE==ENABLE) unfreeze_user_periodic_pipe(); #endif // And return... return ((U8)status); }
/** * @brief Entry point of the USB host management * * The aim is to manage the device target connection and enumeration * depending on the device_state, the function performs the required operations * to get the device enumerated and configured * Once the device is operationnal, the device_state value is DEVICE_READY * This state should be tested by the host task application before performing * any applicative requests to the device. * * @param none * * @return none * * \image html host_task.gif */ void usb_host_task(void) { switch (device_state) { //------------------------------------------------------ // DEVICE_UNATTACHED state // // - Default init state // - Try to give device power supply // case DEVICE_UNATTACHED: Host_clear_device_supported(); // Reset Device status Host_clear_configured(); Host_clear_device_ready(); Usb_clear_all_event(); // Clear all software events new_device_connected=FALSE; selected_device=0; #if (USB_HUB_SUPPORT==ENABLE) nb_hub_present = 0; #endif #if (SOFTWARE_VBUS_CTRL==ENABLE) if( Is_usb_bconnection_error_interrupt()||Is_usb_vbus_error_interrupt()) { Usb_ack_bconnection_error_interrupt(); Usb_ack_vbus_error_interrupt(); Host_clear_vbus_request(); } Usb_disable_vbus_pad(); Usb_enable_manual_vbus(); if(Is_usb_srp_interrupt()) { Usb_ack_srp_interrupt(); Usb_enable_vbus_pad(); Usb_enable_vbus(); device_state=DEVICE_ATTACHED; } #else Usb_enable_vbus(); // Give at least device power supply!!! if(Is_usb_vbus_high()) { device_state=DEVICE_ATTACHED; } // If VBUS ok goto to device connection expectation #endif break; //------------------------------------------------------ // DEVICE_ATTACHED state // // - Vbus is on // - Try to detected device connection // case DEVICE_ATTACHED : if (Is_device_connection() || (force_enumeration==TRUE)) // Device pull-up detected { Host_ack_device_connection(); Host_clear_device_supported(); // Reset Device status Host_clear_configured(); Host_clear_device_ready(); Usb_clear_all_event(); // Clear all software events new_device_connected=FALSE; force_enumeration=FALSE; // Now device is connected, enable disconnection interrupt Host_enable_device_disconnection_interrupt(); Enable_interrupt(); // Reset device status Host_clear_device_supported(); Host_clear_configured(); Host_clear_device_ready(); Host_enable_sof(); // Start Start Of Frame generation Host_enable_sof_interrupt(); // SOF will be detected under interrupt c = 0; while (c<100) // wait 100ms before USB reset { if (Is_usb_event(EVT_HOST_SOF)) { Usb_ack_event(EVT_HOST_SOF); c++; }// Count Start Of frame if (Is_host_emergency_exit() || Is_usb_bconnection_error_interrupt()) {goto device_attached_error;} } Host_disable_device_disconnection_interrupt(); Host_send_reset(); // First USB reset Usb_ack_event(EVT_HOST_SOF); while (Is_host_reset()); // Active wait of end of reset send Host_ack_reset(); //Workaround for some bugly devices with powerless pull up //usually low speed where data line rise slowly and can be interpretaded as disconnection for(c=0;c!=0xFFFF;c++) // Basic Timeout counter { if(Is_usb_event(EVT_HOST_SOF)) //If we detect SOF, device is still alive and connected, just clear false disconnect flag { if(Is_device_disconnection()) { Host_ack_device_connection(); Host_ack_device_disconnection(); break; } } } Host_enable_device_disconnection_interrupt(); // All USB pipes must be reconfigured after a USB reset generation host_configure_pipe(PIPE_CONTROL, \ TYPE_CONTROL, \ TOKEN_SETUP, \ EP_CONTROL, \ SIZE_64, \ ONE_BANK, \ 0 ); c = 0; while (c<100) // wait 100ms after USB reset { if (Is_usb_event(EVT_HOST_SOF)) { Usb_ack_event(EVT_HOST_SOF); c++; }// Count Start Of frame if (Is_host_emergency_exit() || Is_usb_bconnection_error_interrupt()) {goto device_attached_error;} } device_state = DEVICE_POWERED; c=0; } device_attached_error: // Device connection error, or vbus pb -> Retry the connection process from the begining if( Is_usb_bconnection_error_interrupt()||Is_usb_vbus_error_interrupt()||Is_usb_vbus_low()) { Usb_ack_bconnection_error_interrupt(); Usb_enable_vbus_hw_control(); device_state=DEVICE_UNATTACHED; Usb_disable_vbus(); Usb_disable_vbus_pad(); Usb_enable_vbus_pad(); Usb_ack_vbus_error_interrupt(); Usb_enable_vbus(); Usb_disable_vbus_hw_control(); Host_disable_sof(); } break; //------------------------------------------------------ // DEVICE_POWERED state // // - Device connection (attach) as been detected, // - Wait 100ms and configure default control pipe // case DEVICE_POWERED : LOG_STR_CODE(log_device_connected); Host_device_connection_action(); if (Is_usb_event(EVT_HOST_SOF)) { Usb_ack_event(EVT_HOST_SOF); if (c++ >= 100) // Wait 100ms { device_state = DEVICE_DEFAULT; } } break; //------------------------------------------------------ // DEVICE_DEFAULT state // // - Get device descriptor // - Reconfigure Pipe 0 according to Device EP0 // - Attribute device address // case DEVICE_DEFAULT : // Get first device descriptor Host_select_device(0); usb_tree.device[0].ep_ctrl_size=8; if( CONTROL_GOOD == host_get_device_descriptor_uncomplete()) { c = 0; while(c<20) // wait 20ms before USB reset (special buggly devices...) { if (Is_usb_event(EVT_HOST_SOF)) { Usb_ack_event(EVT_HOST_SOF); c++; } if (Is_host_emergency_exit() || Is_usb_bconnection_error_interrupt()) {break;} } Host_disable_device_disconnection_interrupt(); Host_send_reset(); // First USB reset Usb_ack_event(EVT_HOST_SOF); while (Is_host_reset()); // Active wait of end of reset send Host_ack_reset(); //Workaround for some bugly devices with powerless pull up //usually low speed where data line rise slowly and can be interpretaded as disconnection for(c=0;c!=0xFFFF;c++) // Basic Timeout counter { if(Is_usb_event(EVT_HOST_SOF)) //If we detect SOF, device is still alive and connected, just clear false disconnect flag { if(Is_device_disconnection()) { Host_ack_device_connection(); Host_ack_device_disconnection(); break; } } } Host_enable_device_disconnection_interrupt(); c = 0; host_configure_pipe(PIPE_CONTROL, \ TYPE_CONTROL, \ TOKEN_SETUP, \ EP_CONTROL, \ SIZE_64, \ ONE_BANK, \ 0 ); while(c<200) // wait 200ms after USB reset { if (Is_usb_event(EVT_HOST_SOF)) { Usb_ack_event(EVT_HOST_SOF); c++; } if (Is_host_emergency_exit() || Is_usb_bconnection_error_interrupt()) {break;} } usb_tree.device[0].ep_ctrl_size=data_stage[OFFSET_FIELD_MAXPACKETSIZE]; // Give an absolute device address host_set_address(DEVICE_BASE_ADDRESS); usb_tree.device[0].device_address=DEVICE_BASE_ADDRESS; device_state = DEVICE_ADDRESSED; } else { device_state = DEVICE_ERROR; } break; //------------------------------------------------------ // DEVICE_BASE_ADDRESSED state // // - Check if VID PID is in supported list // case DEVICE_ADDRESSED : if (CONTROL_GOOD == host_get_device_descriptor()) { // Detect if the device connected belongs to the supported devices table if (HOST_TRUE == host_check_VID_PID()) { Host_set_device_supported(); Host_device_supported_action(); device_state = DEVICE_CONFIGURED; } else { #if (HOST_STRICT_VID_PID_TABLE==ENABLE) Host_device_not_supported_action(); device_state = DEVICE_ERROR; #else device_state = DEVICE_CONFIGURED; #endif } } else // Can not get device descriptor { device_state = DEVICE_ERROR; } break; //------------------------------------------------------ // DEVICE_CONFIGURED state // // - Configure pipes for the supported interface // - Send Set_configuration() request // - Goto full operating mode (device ready) // case DEVICE_CONFIGURED : if (CONTROL_GOOD == host_get_configuration_descriptor()) { if (HOST_FALSE != host_check_class()) // Class support OK? { usb_tree.nb_device++; #if (HOST_AUTO_CFG_ENDPOINT==ENABLE) if(host_auto_configure_endpoint()) #else Host_set_configured(); // Assumes config is OK with user config if(User_configure_endpoint()) // User call here instead of autoconfig #endif { if (CONTROL_GOOD== host_set_configuration(1)) // Send Set_configuration { //host_set_interface(interface_bound,interface_bound_alt_set); // device and host are now fully configured // goto DEVICE READY normal operation device_state = DEVICE_READY; Host_set_device_ready(); // monitor device disconnection under interrupt Host_enable_device_disconnection_interrupt(); // If user host application requires SOF interrupt event // Keep SOF interrupt enable otherwize, disable this interrupt #if (HOST_CONTINUOUS_SOF_INTERRUPT==DISABLE && USB_HUB_SUPPORT==DISABLE) Host_disable_sof_interrupt(); #endif #if (USB_HUB_SUPPORT==ENABLE) // Check if the connected device is a hub if(Get_class(0)==HUB_CLASS && Get_subclass(0)==0x00 && Get_protocol(0)==0x00) { // Get hub descriptor if( Get_hub_descriptor()==CONTROL_GOOD) { // Power each port of the hub i=data_stage[NB_PORT_OFFSET]; for(c=1;c<=i;c++) { Set_port_feature(PORT_POWER,c); } nb_hub_present = 1; hub_device_address[0]=DEVICE_BASE_ADDRESS; hub_init(nb_hub_present-1); } } else { nb_hub_present = 0; new_device_connected=TRUE; } #else new_device_connected=TRUE; #endif Enable_interrupt(); LOG_STR_CODE(log_device_enumerated); } else// Problem during Set_configuration request... { device_state = DEVICE_ERROR; } } } else // device class not supported... { device_state = DEVICE_ERROR; LOG_STR_CODE(log_device_unsupported); Host_device_class_not_supported_action(); } } else // Can not get configuration descriptors... { device_state = DEVICE_ERROR; } break; //------------------------------------------------------ // DEVICE_READY state // // - Full std operatinf mode // - Nothing to do... // case DEVICE_READY: // Host full std operating mode! new_device_connected=FALSE; #if (USB_HUB_SUPPORT==ENABLE) f_hub_port_disconnect=FALSE; // If one hub is present in the USB tree and the period interval // for the interrupt hub endpoint occurs if(nb_hub_present && hub_interrupt_sof==0) { saved_device=selected_device; // Backup user selected device for(j=1;j<=nb_hub_present;j++) { for(i=0;i<MAX_DEVICE_IN_USB_TREE;i++) { if(usb_tree.device[i].device_address==hub_device_address[j-1]) break; } Host_select_device(i); Host_select_pipe(usb_tree.device[i].interface[0].ep[0].pipe_number); Host_ack_nak_received(); Host_ack_in_received(); Host_unfreeze_pipe(); Host_send_in(); while(1) { if(Is_host_nak_received()) break; if(Is_host_emergency_exit()) break; if(Is_host_in_received()) break; } Host_freeze_pipe(); if(Is_host_nak_received()) { Host_ack_nak_received(); } if(Is_host_in_received()) { if(Is_host_stall()==FALSE) { c=Host_read_byte(); } Host_ack_in_received(); hub_manage_port_change_status(c,j); } } // for all hub Host_select_device(saved_device); // Restore user selected device #if (USER_PERIODIC_PIPE==ENABLE) unfreeze_user_periodic_pipe(); #endif } #endif break; //------------------------------------------------------ // DEVICE_ERROR state // // - Error state // - Do custom action call (probably go to default mode...) // case DEVICE_ERROR : // TODO !!!! #if (HOST_ERROR_RESTART==ENABLE) device_state=DEVICE_UNATTACHED; #endif Host_device_error_action(); break; //------------------------------------------------------ // DEVICE_SUSPENDED state // // - Host application request to suspend the device activity // - State machine comes here thanks to Host_request_suspend() // case DEVICE_SUSPENDED : if(Is_device_supports_remote_wakeup()) // If the connected device supports remote wake up { host_set_feature_remote_wakeup(); // Enable this feature... } LOG_STR_CODE(log_going_to_suspend); c = Is_host_sof_interrupt_enabled(); //Save current sof interrupt enable state Host_disable_sof_interrupt(); Host_ack_sof(); Host_disable_sof(); // Stop start of frame generation, this generates the suspend state Host_ack_hwup(); Host_enable_hwup_interrupt(); // Enable host wake-up interrupt // (this is the unique USB interrupt able to wake up the CPU core from power-down mode) Usb_freeze_clock(); Stop_pll(); Host_suspend_action(); // Custom action here! (for example go to power-save mode...) device_state=DEVICE_WAIT_RESUME; // wait for device resume event break; //------------------------------------------------------ // DEVICE_WAIT_RESUME state // // - Wait in this state till the host receives an upstream resume from the device // - or the host software request the device to resume // case DEVICE_WAIT_RESUME : if(Is_usb_event(EVT_HOST_HWUP)|| Is_host_request_resume())// Remote wake up has been detected // or Local resume request has been received { if(Is_host_request_resume()) // Not a remote wakeup, but an host application request { Host_disable_hwup_interrupt(); // Wake up interrupt should be disable host is now wake up ! // CAUTION HWUP can be cleared only when USB clock is active Pll_start_auto(); // First Restart the PLL for USB operation Wait_pll_ready(); // Get sure pll is lock Usb_unfreeze_clock(); // Enable clock on USB interface Host_ack_hwup(); // Clear HWUP interrupt flag } Host_enable_sof(); Host_send_resume(); // Send down stream resume while (Is_host_down_stream_resume()==FALSE); // Wait Down stream resume sent Host_ack_remote_wakeup(); // Ack remote wake-up reception Host_ack_request_resume(); // Ack software request Host_ack_down_stream_resume(); // Ack down stream resume sent Usb_ack_event(EVT_HOST_HWUP); // Ack software event if(c) { Host_enable_sof_interrupt(); } // Restore SOF interrupt enable state before suspend device_state=DEVICE_READY; // Come back to full operating mode LOG_STR_CODE(log_usb_resumed); } break; //------------------------------------------------------ // DEVICE_DISCONNECTED state // // - Device disconnection has been detected // - Run scheduler in this state at least two times to get sure event is detected by all host application tasks // - Go to DEVICE_DISCONNECTED_ACK state before DEVICE_UNATTACHED, to get sure scheduler calls all app tasks... // case DEVICE_DISCONNECTED : device_state = DEVICE_DISCONNECTED_ACK; break; //------------------------------------------------------ // DEVICE_DISCONNECTED_ACK state // // - Device disconnection has been detected and managed bu applicatives tasks // - Go to DEVICE_UNATTACHED state // case DEVICE_DISCONNECTED_ACK : device_state = DEVICE_UNATTACHED; break; //------------------------------------------------------ // default state // // - Default case: ERROR // - Goto no device state // default : device_state = DEVICE_UNATTACHED; break; } }
//------------------------------------------------------------------------------ /// USB interrupt subroutine /// /// This function is called each time a USB interrupt occurs. /// The following USB DEVICE events are taken in charge: /// - VBus On / Off /// - Start Of Frame /// - Suspend /// - Wake-Up /// - Resume /// - Reset /// - Start of frame /// /// The following USB HOST events are taken in charge: /// - Device connection /// - Device Disconnection /// - Start Of Frame /// - ID pin change /// - SOF (or Keep alive in low speed) sent /// - Wake up on USB line detected /// /// The following USB HOST events are taken in charge: /// - HNP success (Role Exchange) /// - HNP failure (HNP Error) /// /// For each event, the user can launch an action by completing /// the associate define (See conf_usb.h file to add action upon events) /// /// Note: Only interrupts events that are enabled are processed //------------------------------------------------------------------------------ void usb_general_interrupt(void) { //TRACE_DEBUG("usb_general_interrupt\n\r"); // ---------- DEVICE events management ----------------------------------- // ----------------------------------------------------------------------- //- VBUS state detection // ----------------------------------------------------------------------- /// Arbitrer // ----------------------------------------------------------------------- if (Is_usb_vbus_transition() && Is_usb_vbus_interrupt_enabled() && Is_usb_id_device()) { Usb_ack_vbus_transition(); if (Is_usb_vbus_high()) { usb_connected = TRUE; Usb_vbus_on_action(); Usb_send_event(EVT_USB_POWERED); //jcb Usb_enable_reset_interrupt(); //usb_start_device(); USBD_Connect();//Usb_attach(); } else { TRACE_DEBUG("VBUS low\n\r"); USBD_Disconnect(); Usb_device_stop_hnp(); TRACE_DEBUG("Usb_select_device4\n\r"); Usb_select_device(); Clear_all_user_request(); Usb_vbus_off_action(); usb_connected = FALSE; usb_configuration_nb = 0; Usb_send_event(EVT_USB_UNPOWERED); } } // ----------------------------------------------------------------------- /// Device // ----------------------------------------------------------------------- // - Device start of frame received if (Is_usb_sof() && Is_sof_interrupt_enabled()) { // TRACE_DEBUG_WP("F"); // device Usb_ack_sof(); Usb_sof_action(); //sof_seen_in_session = TRUE; otg_last_sof_received = UDFNUML; // store last frame number received } // ----------------------------------------------------------------------- /// Device // ----------------------------------------------------------------------- // - Device Suspend event (no more USB activity detected) if (Is_usb_suspend()) { //&& Is_suspend_interrupt_enabled()) { //TRACE_DEBUG_WP("D\n\r"); // 1st : B-PERIPH mode ? if (Is_usb_id_device()) { // HNP Handler TRACE_DEBUG("HNP Handler\n\r"); //TRACE_DEBUG("device_state = %d\n\r", device_state); //TRACE_DEBUG("b_uut_device_state = %d\n\r", b_uut_device_state); if (Is_host_requested_hnp() // "b_hnp_enable" feature received && (Is_session_started_with_srp() || Is_user_requested_hnp() )) { if (otg_device_nb_hnp_retry == 0) { otg_features_supported &= ~USBFeatureRequest_OTG_B_HNP_ENABLE; } else { Ack_user_request_hnp(); Usb_ack_hnp_error_interrupt(); Usb_ack_role_exchange_interrupt(); Usb_enable_role_exchange_interrupt(); Usb_enable_hnp_error_interrupt(); Usb_device_initiate_hnp(); otg_device_nb_hnp_retry--; } } else { // Remote wake-up handler //TRACE_DEBUG("Remote wake-up handler\n\r"); //TRACE_DEBUG("device_state = %d\n\r", device_state); //TRACE_DEBUG("b_uut_device_state = %d\n\r", b_uut_device_state); if ((remote_wakeup_feature == ENABLE) && (usb_configuration_nb != 0)) { //TRACE_DEBUG("enabled\n\r"); // After that user can execute "Usb_initiate_remote_wake_up()" to initiate a remote wake-up // Note that the suspend interrupt flag SUSPI must still be set to enable upstream resume // So the SUSPE enable bit must be cleared to avoid redundant interrupt // **************** // Please note also that is Vbus is lost during an upstream resume (Host disconnection), // the RMWKUP bit (used to initiate remote wake up and that is normally cleared by hardware when sent) // remains set after the event, so that a good way to handle this feature is : // Usb_initiate_remote_wake_up(); // while (Is_usb_pending_remote_wake_up()) // { // if (Is_usb_vbus_low()) // { // // Emergency action (reset macro, etc.) if Vbus lost during resuming // break; // } // } // Usb_ack_remote_wake_up_start(); // **************** } else { //TRACE_DEBUG("disabled: %d %d\n\r", usb_configuration_nb, remote_wakeup_feature); // No remote wake-up supported Usb_send_event(EVT_USB_SUSPEND); } } } else { //TRACE_DEBUG("ici\n\r"); // A-PERIPH mode (will cause a session end, handled in usb_host_task.c) Usb_send_event(EVT_USB_SUSPEND); Usb_suspend_action(); //jcb Usb_ack_suspend(); } } // ----------------------------------------------------------------------- /// Device // ----------------------------------------------------------------------- // - Wake up event (USB activity detected): Used to resume if (Is_usb_wake_up() && Is_swake_up_interrupt_enabled()) { TRACE_DEBUG("W\n\r"); Usb_unfreeze_clock(); Usb_send_event(EVT_USB_WAKE_UP); } // ----------------------------------------------------------------------- /// Device // ----------------------------------------------------------------------- // - Resume state bus detection if (Is_usb_resume() && Is_resume_interrupt_enabled()) { TRACE_DEBUG("Resume state bus detect\n\r"); Usb_send_event(EVT_USB_RESUME); } // ----------------------------------------------------------------------- /// Device // ----------------------------------------------------------------------- // - USB bus reset detection if (Is_usb_reset()&& Is_reset_interrupt_enabled()) { TRACE_DEBUG_WP("B\n\r"); if (Is_usb_id_host()) { //TRACE_DEBUG_WP("id_host\n\r"); dev_configure_endpoint(EP_CONTROL, TYPE_CONTROL, DIRECTION_OUT, SIZE_64, ONE_BANK, NYET_DISABLED); } // First initialization is important to be synchronized // A reset must first have been received if (device_state == A_PERIPHERAL) { //TRACE_DEBUG_WP("r A_PERIPHERAL\n\r"); otg_last_sof_received = UDFNUML; otg_last_sof_stored = UDFNUML; Usb_ack_sof(); Usb_enable_sof_interrupt(); reset_received = TRUE; Timer16_set_counter(0); } Usb_reset_action(); Usb_send_event(EVT_USB_RESET); } // ---------- OTG events management ------------------------------------ // --------------------------------------------------------------------- // ----------------------------------------------------------------------- /// Arbitrer // ----------------------------------------------------------------------- // - OTG HNP Success detection if (Is_usb_role_exchange_interrupt() && Is_role_exchange_interrupt_enabled()) { // TRACE_DEBUG("OTG HNP detect\n\r"); Usb_ack_role_exchange_interrupt(); Host_ack_device_connection(); Host_ack_device_disconnection(); Otg_send_event(EVT_OTG_HNP_SUCCESS); End_session_with_srp(); Clear_otg_features_from_host(); if (Is_usb_id_host()) { // HOST (A- or B-) mode if ((device_state != A_PERIPHERAL) && (device_state != A_END_HNP_WAIT_VFALL)) { static volatile unsigned int jcb; // Current mode is A-HOST, device will take the A-PERIPHERAL role b_uut_device_state = B_PERIPHERAL; device_state = A_PERIPHERAL; usb_connected = FALSE; usb_configuration_nb = 0; Usb_select_device(); USBD_Connect();//Usb_attach(); Usb_unfreeze_clock(); Usb_disable_role_exchange_interrupt(); Usb_disable_hnp_error_interrupt(); Usb_device_stop_hnp(); Usb_ack_reset(); Timer16_set_counter(0); Usb_freeze_clock(); // USB clock can be freezed to slow down events and condition detection //jcb while (Timer16_get_counter_low() != 20); jcb=0; while( jcb <100000){ jcb++; } Usb_unfreeze_clock(); reset_received = FALSE; Usb_disable_sof_interrupt(); // will be set in the next OTG Timer IT (mandatory) Usb_enable_suspend_interrupt(); Usb_enable_reset_interrupt(); dev_configure_endpoint(EP_CONTROL, TYPE_CONTROL, DIRECTION_OUT, SIZE_64, ONE_BANK, NYET_DISABLED); } } else { // In B_HOST mode, the HNPREQ bit must not be cleared because it releases the bus in suspend mode (and sof can't start) if ((b_uut_device_state != B_HOST) && (b_uut_device_state != B_END_HNP_SUSPEND)) { static volatile unsigned int jcb2; // Current mode is B-PERIPHERAL, device will go into B-HOST role End_session_with_srp(); Clear_otg_features_from_host(); b_uut_device_state = B_HOST; device_state = DEVICE_ATTACHED; usb_connected = FALSE; usb_configuration_nb = 0; TRACE_DEBUG("Select host 3\n\r"); Usb_select_host(); TRACE_DEBUG("Send reset\n\r"); Host_send_reset(); // send the first RESET while (Host_is_reset()); TRACE_DEBUG("Reset passed\n\r"); jcb2=0; while( jcb2 <1000000){ jcb2++; } Host_enable_sof(); // start Host (sof) Usb_disable_role_exchange_interrupt(); Usb_disable_hnp_error_interrupt(); Clear_all_user_request(); TRACE_DEBUG("Select host 3\n\r"); } } } // ----------------------------------------------------------------------- /// Arbitrer // ----------------------------------------------------------------------- // - OTG HNP Failure detection if (Is_usb_hnp() && Is_usb_hnp_error_interrupt()&& Is_hnp_error_interrupt_enabled()) { TRACE_DEBUG("OTG HNP failure\n\r"); Usb_device_stop_hnp(); Usb_disable_role_exchange_interrupt(); Usb_disable_hnp_error_interrupt(); Usb_ack_hnp_error_interrupt(); if (Is_usb_id_device()) { Otg_send_event(EVT_OTG_HNP_ERROR); Clear_all_user_request(); } } // ---------- HOST events management ----------------------------------- // --------------------------------------------------------------------- // ----------------------------------------------------------------------- /// Arbitrer // ----------------------------------------------------------------------- // - ID pin change detection if(Is_usb_id_transition()&&Is_usb_id_interrupt_enabled()) { TRACE_DEBUG("ID pin change\n\r"); TRACE_DEBUG("device_state = %d\n\r", device_state); TRACE_DEBUG("b_uut_device_state = %d\n\r", b_uut_device_state); Usb_device_stop_hnp(); Clear_all_user_request(); if(Is_usb_id_device()) { g_usb_mode = USB_MODE_DEVICE; } else { g_usb_mode = USB_MODE_HOST; } Usb_ack_id_transition(); if( g_usb_mode != g_old_usb_mode) { // Basic Debounce if(Is_usb_id_device()) { // Going into device mode Usb_send_event(EVT_USB_DEVICE_FUNCTION); b_uut_device_state = B_IDLE; device_state = DEVICE_UNATTACHED; id_changed_to_host_event = DISABLE; } else { // Going into host mode b_uut_device_state = B_IDLE; device_state = DEVICE_UNATTACHED; Usb_send_event(EVT_USB_HOST_FUNCTION); id_changed_to_host_event = ENABLE; } Usb_id_transition_action(); TRACE_INFO("Pin Id changed\n\r"); } } // ----------------------------------------------------------------------- /// Host // ----------------------------------------------------------------------- // - The device has been disconnected // JCB to be fix if(Is_device_disconnection() && Is_host_device_disconnection_interrupt_enabled()) { TRACE_DEBUG("device disconnect\n\r"); host_disable_all_pipe(); Host_ack_device_disconnection(); device_state=DEVICE_DISCONNECTED; Usb_send_event(EVT_HOST_DISCONNECTION); TRACE_INFO("Device disconnected\n\r"); Host_device_disconnection_action(); Clear_all_user_request(); } // ----------------------------------------------------------------------- /// Host // ----------------------------------------------------------------------- // - Device connection if(Is_device_connection() && Is_host_device_connection_interrupt_enabled()) { TRACE_DEBUG("device connect\n\r"); Host_ack_device_connection(); host_disable_all_pipe(); Host_device_connection_action(); } // ----------------------------------------------------------------------- /// Host // ----------------------------------------------------------------------- // - Host Start of frame has been sent if (Is_host_sof() && Is_host_sof_interrupt_enabled()) { //TRACE_DEBUG_WP("_"); // host Host_ack_sof(); Usb_send_event(EVT_HOST_SOF); private_sof_counter++; // delay timeout management for interrupt tranfer mode in host mode #if ((USB_HOST_PIPE_INTERRUPT_TRANSFER==ENABLE) && (TIMEOUT_DELAY_ENABLE==ENABLE)) if (private_sof_counter>=250) { // Count 1/4 sec private_sof_counter=0; for(i=0;i<MAX_EP_NB;i++) { if(it_pipe_str[i].enable==ENABLE) { save_pipe_nb=Host_get_selected_pipe(); Host_select_pipe(i); if((++it_pipe_str[i].timeout>TIMEOUT_DELAY) && (Host_get_pipe_type()!=TYPE_INTERRUPT)) { it_pipe_str[i].enable=DISABLE; it_pipe_str[i].status=PIPE_DELAY_TIMEOUT; Host_stop_pipe_interrupt(i); if (is_any_interrupt_pipe_active()==FALSE) { // If no more transfer is armed if (g_sav_int_sof_enable==FALSE) { Host_disable_sof_interrupt(); } } it_pipe_str[i].handle(PIPE_DELAY_TIMEOUT,it_pipe_str[i].nb_byte_processed); } Host_select_pipe(save_pipe_nb); } } } #endif // (USB_HOST_PIPE_INTERRUPT_TRANSFER==ENABLE) && (TIMEOUT_DELAY_ENABLE==ENABLE)) Host_sof_action(); } // ----------------------------------------------------------------------- /// Host // ----------------------------------------------------------------------- // - Host Wake-up has been received if (Is_host_hwup() && Is_host_hwup_interrupt_enabled()) { TRACE_DEBUG("Host wake up\n\r"); Host_disable_hwup_interrupt(); // Wake up interrupt should be disable host is now wake up ! Host_disable_remote_wakeup_interrupt(); // CAUTION HWUP can be cleared only when USB clock is active (not frozen)! Usb_unfreeze_clock(); // Enable clock on USB interface Host_enable_sof(); // start sending SOF Host_ack_hwup(); // Clear HWUP interrupt flag Host_ack_remote_wakeup(); Usb_send_event(EVT_HOST_HWUP); // Send software event Usb_send_event(EVT_HOST_REMOTE_WAKEUP); Host_hwup_action(); // Map custom action if (Is_usb_hnp()) { Usb_host_reject_hnp(); Usb_disable_hnp_error_interrupt(); Usb_disable_role_exchange_interrupt(); } Host_send_resume(); } // ----------------------------------------------------------------------- /// Host // ----------------------------------------------------------------------- // Remote Wake Up has been received if (Is_host_remote_wakeup_interrupt_enabled() && Is_host_remote_wakeup()) { TRACE_DEBUG("Remote wake up\n\r"); Host_disable_remote_wakeup_interrupt(); Host_disable_hwup_interrupt(); Host_ack_remote_wakeup(); Host_ack_hwup(); // Clear HWUP interrupt flag Usb_unfreeze_clock(); // Enable clock on USB interface Host_enable_sof(); // start sending SOF Usb_send_event(EVT_HOST_REMOTE_WAKEUP); Usb_send_event(EVT_HOST_HWUP); // Send software event if (Is_usb_hnp()) { Usb_host_reject_hnp(); Usb_disable_hnp_error_interrupt(); Usb_disable_role_exchange_interrupt(); } Host_send_resume(); } }
__interrupt void usb_general_interrupt() #endif { #if (USB_HOST_PIPE_INTERRUPT_TRANSFER == ENABLE) U8 i; U8 save_pipe_nb; #endif // ---------- DEVICE events management ----------------------------------- #if (USB_DEVICE_FEATURE == ENABLED) //- VBUS state detection if (Is_usb_vbus_transition() && Is_usb_vbus_interrupt_enabled()) { Usb_ack_vbus_transition(); if (Is_usb_vbus_high()) { usb_connected = TRUE; Usb_vbus_on_action(); Usb_send_event(EVT_USB_POWERED); Usb_enable_reset_interrupt(); usb_start_device(); Usb_attach(); } else { Usb_vbus_off_action(); usb_connected = FALSE; usb_configuration_nb = 0; Usb_send_event(EVT_USB_UNPOWERED); } } // - Device start of frame received if (Is_usb_sof() && Is_sof_interrupt_enabled()) { Usb_ack_sof(); Usb_sof_action(); } // - Device Suspend event (no more USB activity detected) if (Is_usb_suspend() && Is_suspend_interrupt_enabled()) { Usb_ack_suspend(); Usb_enable_wake_up_interrupt(); Usb_ack_wake_up(); // clear wake up to detect next event Usb_freeze_clock(); Usb_send_event(EVT_USB_SUSPEND); Usb_suspend_action(); } // - Wake up event (USB activity detected): Used to resume if (Is_usb_wake_up() && Is_swake_up_interrupt_enabled()) { Usb_unfreeze_clock(); Usb_ack_wake_up(); Usb_disable_wake_up_interrupt(); Usb_wake_up_action(); Usb_send_event(EVT_USB_WAKE_UP); } // - Resume state bus detection if (Is_usb_resume() && Is_resume_interrupt_enabled()) { Usb_disable_wake_up_interrupt(); Usb_ack_resume(); Usb_disable_resume_interrupt(); Usb_resume_action(); Usb_send_event(EVT_USB_RESUME); } // - USB bus reset detection if (Is_usb_reset()&& Is_reset_interrupt_enabled()) { Usb_ack_reset(); usb_init_device(); Usb_reset_action(); Usb_send_event(EVT_USB_RESET); } #endif// End DEVICE FEATURE MODE // ---------- HOST events management ----------------------------------- #if (USB_HOST_FEATURE == ENABLED && USB_DEVICE_FEATURE == ENABLED) // - ID pin change detection if(Is_usb_id_transition()&&Is_usb_id_interrupt_enabled()) { if(Is_usb_id_device()) { g_usb_mode=USB_MODE_DEVICE;} else { g_usb_mode=USB_MODE_HOST;} Usb_ack_id_transition(); if( g_usb_mode != g_old_usb_mode) // Basic Debounce { if(Is_usb_id_device()) // Going to device mode { Usb_send_event(EVT_USB_DEVICE_FUNCTION); } else // Going to host mode { Usb_send_event(EVT_USB_HOST_FUNCTION); } Usb_id_transition_action(); LOG_STR_CODE(log_id_change); #if ( ID_PIN_CHANGE_GENERATE_RESET == ENABLE) // Hot ID transition generates wdt reset #ifndef AVRGCC Wdt_change_16ms(); while(1); #else Wdt_change_enable(); while(1); #endif #endif } } #endif #if (USB_HOST_FEATURE == ENABLED) // - The device has been disconnected if(Is_device_disconnection() && Is_host_device_disconnection_interrupt_enabled()) { host_disable_all_pipe(); Host_ack_device_disconnection(); device_state=DEVICE_DISCONNECTED; Usb_send_event(EVT_HOST_DISCONNECTION); LOG_STR_CODE(log_device_disconnect); Host_device_disconnection_action(); } // - Device connection if(Is_device_connection() && Is_host_device_connection_interrupt_enabled()) { Host_ack_device_connection(); host_disable_all_pipe(); Host_device_connection_action(); } // - Host Start of frame has been sent if (Is_host_sof() && Is_host_sof_interrupt_enabled()) { Host_ack_sof(); Usb_send_event(EVT_HOST_SOF); private_sof_counter++; // delay timeout management for interrupt tranfer mode in host mode #if ((USB_HOST_PIPE_INTERRUPT_TRANSFER==ENABLE) && (TIMEOUT_DELAY_ENABLE==ENABLE)) if (private_sof_counter>=250) // Count 1/4 sec { private_sof_counter=0; for(i=0;i<MAX_EP_NB;i++) { if(it_pipe_str[i].enable==ENABLE) { save_pipe_nb=Host_get_selected_pipe(); Host_select_pipe(i); if((++it_pipe_str[i].timeout>TIMEOUT_DELAY) && (Host_get_pipe_type()!=TYPE_INTERRUPT)) { it_pipe_str[i].enable=DISABLE; it_pipe_str[i].status=PIPE_DELAY_TIMEOUT; Host_stop_pipe_interrupt(i); if (is_any_interrupt_pipe_active()==FALSE) // If no more transfer is armed { if (g_sav_int_sof_enable==FALSE) { Host_disable_sof_interrupt(); } } it_pipe_str[i].handle(PIPE_DELAY_TIMEOUT,it_pipe_str[i].nb_byte_processed); } Host_select_pipe(save_pipe_nb); } } } #endif // (USB_HOST_PIPE_INTERRUPT_TRANSFER==ENABLE) && (TIMEOUT_DELAY_ENABLE==ENABLE)) Host_sof_action(); } // - Host Wake-up has been received if (Is_host_hwup() && Is_host_hwup_interrupt_enabled()) { Host_disable_hwup_interrupt(); // Wake up interrupt should be disable host is now wake up ! // CAUTION HWUP can be cleared only when USB clock is active (not frozen)! Pll_start_auto(); // First Restart the PLL for USB operation Wait_pll_ready(); // Get sure pll is lock Usb_unfreeze_clock(); // Enable clock on USB interface Host_ack_hwup(); // Clear HWUP interrupt flag Usb_send_event(EVT_HOST_HWUP); // Send software event Host_hwup_action(); // Map custom action } #endif // End HOST FEATURE MODE }