diff options
| author | HiFiPhile <[email protected]> | 2024-09-08 17:15:28 +0200 |
|---|---|---|
| committer | GitHub <[email protected]> | 2024-09-08 17:15:28 +0200 |
| commit | 7867464694a5889f5974385e962f40c9a064c7b2 (patch) | |
| tree | 39e469aad8c7daa89c62e6a55a70dd1c0f32c8bb /src | |
| parent | 6d4e2f6c16e239889195fcfbd81b4d27b6ff1979 (diff) | |
| parent | 3eea46056ea20aa12b73eea7c01d6c6e5b2d490a (diff) | |
Merge branch 'master' into dwc2_dma
Diffstat (limited to 'src')
46 files changed, 3111 insertions, 4938 deletions
diff --git a/src/class/audio/audio.h b/src/class/audio/audio.h index d6f3e22e2..2f97c0f23 100644 --- a/src/class/audio/audio.h +++ b/src/class/audio/audio.h @@ -489,7 +489,7 @@ typedef enum AUDIO_DATA_FORMAT_TYPE_I_IEEE_FLOAT = (uint32_t) (1 << 2), AUDIO_DATA_FORMAT_TYPE_I_ALAW = (uint32_t) (1 << 3), AUDIO_DATA_FORMAT_TYPE_I_MULAW = (uint32_t) (1 << 4), - AUDIO_DATA_FORMAT_TYPE_I_RAW_DATA = 0x80000000, + AUDIO_DATA_FORMAT_TYPE_I_RAW_DATA = 0x80000000u, } audio_data_format_type_I_t; /// All remaining definitions are taken from the descriptor descriptions in the UAC2 main specification @@ -640,7 +640,7 @@ typedef enum AUDIO_CHANNEL_CONFIG_BOTTOM_CENTER = 0x01000000, AUDIO_CHANNEL_CONFIG_BACK_LEFT_OF_CENTER = 0x02000000, AUDIO_CHANNEL_CONFIG_BACK_RIGHT_OF_CENTER = 0x04000000, - AUDIO_CHANNEL_CONFIG_RAW_DATA = 0x80000000, + AUDIO_CHANNEL_CONFIG_RAW_DATA = 0x80000000u, } audio_channel_config_t; /// AUDIO Channel Cluster Descriptor (4.1) diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index 4a383c3c7..8c86de433 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -2,6 +2,7 @@ * The MIT License (MIT) * * Copyright (c) 2020 Reinhard Panhuber, Jerzy Kasenberg + * Copyright (c) 2023 HiFiPhile * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -120,23 +121,23 @@ // EP IN software buffers and mutexes #if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING #if CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0 - IN_SW_BUF_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ]; + tu_static IN_SW_BUF_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ]; #if CFG_FIFO_MUTEX - osal_mutex_def_t ep_in_ff_mutex_wr_1; // No need for read mutex as only USB driver reads from FIFO + tu_static osal_mutex_def_t ep_in_ff_mutex_wr_1; // No need for read mutex as only USB driver reads from FIFO #endif #endif // CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0 #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0 - IN_SW_BUF_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ]; + tu_static IN_SW_BUF_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ]; #if CFG_FIFO_MUTEX - osal_mutex_def_t ep_in_ff_mutex_wr_2; // No need for read mutex as only USB driver reads from FIFO + tu_static osal_mutex_def_t ep_in_ff_mutex_wr_2; // No need for read mutex as only USB driver reads from FIFO #endif #endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0 #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0 - IN_SW_BUF_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ]; + tu_static IN_SW_BUF_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ]; #if CFG_FIFO_MUTEX - osal_mutex_def_t ep_in_ff_mutex_wr_3; // No need for read mutex as only USB driver reads from FIFO + tu_static osal_mutex_def_t ep_in_ff_mutex_wr_3; // No need for read mutex as only USB driver reads from FIFO #endif #endif // CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0 #endif // CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING @@ -146,38 +147,38 @@ // - the software encoding is used - in this case the linear buffers serve as a target memory where logical channels are encoded into #if CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_ENCODING) #if CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX > 0 - CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX]; + tu_static CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX]; #endif #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX > 0 - CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX]; + tu_static CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX]; #endif #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX > 0 - CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX]; + tu_static CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX]; #endif #endif // CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING) // EP OUT software buffers and mutexes #if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING #if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0 - OUT_SW_BUF_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ]; + tu_static OUT_SW_BUF_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ]; #if CFG_FIFO_MUTEX - osal_mutex_def_t ep_out_ff_mutex_rd_1; // No need for write mutex as only USB driver writes into FIFO + tu_static osal_mutex_def_t ep_out_ff_mutex_rd_1; // No need for write mutex as only USB driver writes into FIFO #endif #endif // CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0 #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0 - OUT_SW_BUF_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ]; + tu_static OUT_SW_BUF_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ]; #if CFG_FIFO_MUTEX - osal_mutex_def_t ep_out_ff_mutex_rd_2; // No need for write mutex as only USB driver writes into FIFO + tu_static osal_mutex_def_t ep_out_ff_mutex_rd_2; // No need for write mutex as only USB driver writes into FIFO #endif #endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0 #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0 - OUT_SW_BUF_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ]; + tu_static OUT_SW_BUF_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ]; #if CFG_FIFO_MUTEX - osal_mutex_def_t ep_out_ff_mutex_rd_3; // No need for write mutex as only USB driver writes into FIFO + tu_static osal_mutex_def_t ep_out_ff_mutex_rd_3; // No need for write mutex as only USB driver writes into FIFO #endif #endif // CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0 #endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING @@ -187,89 +188,89 @@ // - the software encoding is used - in this case the linear buffers serve as a target memory where logical channels are encoded into #if CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING) #if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX > 0 - CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX]; + tu_static CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX]; #endif #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX > 0 - CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX]; + tu_static CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX]; #endif #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX > 0 - CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX]; + tu_static CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX]; #endif #endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING) // Control buffers -CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_1[CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ]; +tu_static CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_1[CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ]; #if CFG_TUD_AUDIO > 1 -CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_2[CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ]; +tu_static CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_2[CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ]; #endif #if CFG_TUD_AUDIO > 2 -CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_3[CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ]; +tu_static CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_3[CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ]; #endif // Active alternate setting of interfaces -uint8_t alt_setting_1[CFG_TUD_AUDIO_FUNC_1_N_AS_INT]; +tu_static uint8_t alt_setting_1[CFG_TUD_AUDIO_FUNC_1_N_AS_INT]; #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_N_AS_INT > 0 -uint8_t alt_setting_2[CFG_TUD_AUDIO_FUNC_2_N_AS_INT]; +tu_static uint8_t alt_setting_2[CFG_TUD_AUDIO_FUNC_2_N_AS_INT]; #endif #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_N_AS_INT > 0 -uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT]; +tu_static uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT]; #endif // Software encoding/decoding support FIFOs #if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING #if CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0 - CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ]; - tu_fifo_t tx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO]; + tu_static CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ]; + tu_static tu_fifo_t tx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO]; #if CFG_FIFO_MUTEX - osal_mutex_def_t tx_supp_ff_mutex_wr_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO + tu_static osal_mutex_def_t tx_supp_ff_mutex_wr_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO #endif #endif #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0 - CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ]; - tu_fifo_t tx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO]; + tu_static CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ]; + tu_static tu_fifo_t tx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO]; #if CFG_FIFO_MUTEX - osal_mutex_def_t tx_supp_ff_mutex_wr_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO + tu_static osal_mutex_def_t tx_supp_ff_mutex_wr_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO #endif #endif #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ > 0 - CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ]; - tu_fifo_t tx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO]; + tu_static CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ]; + tu_static tu_fifo_t tx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO]; #if CFG_FIFO_MUTEX - osal_mutex_def_t tx_supp_ff_mutex_wr_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO + tu_static osal_mutex_def_t tx_supp_ff_mutex_wr_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO #endif #endif #endif #if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING #if CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0 - CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ]; - tu_fifo_t rx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO]; + tu_static CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ]; + tu_static tu_fifo_t rx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO]; #if CFG_FIFO_MUTEX - osal_mutex_def_t rx_supp_ff_mutex_rd_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO + tu_static osal_mutex_def_t rx_supp_ff_mutex_rd_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO #endif #endif #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0 - CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ]; - tu_fifo_t rx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO]; + tu_static CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ]; + tu_static tu_fifo_t rx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO]; #if CFG_FIFO_MUTEX - osal_mutex_def_t rx_supp_ff_mutex_rd_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO + tu_static osal_mutex_def_t rx_supp_ff_mutex_rd_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO #endif #endif #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ > 0 - CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ]; - tu_fifo_t rx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO]; + tu_static CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ]; + tu_static tu_fifo_t rx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO]; #if CFG_FIFO_MUTEX - osal_mutex_def_t rx_supp_ff_mutex_rd_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO + tu_static osal_mutex_def_t rx_supp_ff_mutex_rd_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO #endif #endif #endif @@ -302,32 +303,18 @@ typedef struct bool mounted; // Device opened - /*------------- From this point, data is not cleared by bus reset -------------*/ - uint16_t desc_length; // Length of audio function descriptor - // Buffer for control requests - uint8_t * ctrl_buf; - uint8_t ctrl_buf_sz; - - // Current active alternate settings - uint8_t * alt_setting; // We need to save the current alternate setting this way, because it is possible that there are AS interfaces which do not have an EP! - - // EP Transfer buffers and FIFOs -#if CFG_TUD_AUDIO_ENABLE_EP_OUT -#if !CFG_TUD_AUDIO_ENABLE_DECODING - tu_fifo_t ep_out_ff; -#endif - #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP struct { - CFG_TUSB_MEM_ALIGN uint32_t value; // Feedback value for asynchronous mode (in 16.16 format). + CFG_TUSB_MEM_ALIGN uint32_t send_buf; + uint32_t value; // Feedback value for asynchronous mode (in 16.16 format). uint32_t min_value; // min value according to UAC2 FMT-2.0 section 2.3.1.1. uint32_t max_value; // max value according to UAC2 FMT-2.0 section 2.3.1.1. uint8_t frame_shift; // bInterval-1 in unit of frame (FS), micro-frame (HS) uint8_t compute_method; - + bool format_correction; union { uint8_t power_of_2; // pre-computed power of 2 shift float float_const; // pre-computed float constant @@ -337,28 +324,17 @@ typedef struct uint32_t mclk_freq; }fixed; -#if 0 // implement later struct { - uint32_t nominal_value; - uint32_t threshold_bytes; + uint32_t nom_value; // In 16.16 format + uint32_t fifo_lvl_avg; // In 16.16 format + uint16_t fifo_lvl_thr; // fifo level threshold + uint16_t rate_const[2]; // pre-computed feedback/fifo_depth rate }fifo_count; -#endif }compute; } feedback; #endif // CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP -#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT - -#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING - tu_fifo_t ep_in_ff; -#endif - - // Audio control interrupt buffer - no FIFO - 6 Bytes according to UAC 2 specification (p. 74) -#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP - CFG_TUSB_MEM_ALIGN uint8_t ep_int_buf[6]; -#endif - // Decoding parameters - parameters are set when alternate AS interface is set by host // Coding is currently only supported for EP. Software coding corresponding to AS interfaces without EPs are not supported currently. #if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING @@ -367,8 +343,7 @@ typedef struct #if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING audio_data_format_type_I_t format_type_I_rx; - uint8_t n_bytes_per_sampe_rx; - uint8_t n_channels_per_ff_rx; + uint8_t n_bytes_per_sample_rx; uint8_t n_ff_used_rx; #endif #endif @@ -384,26 +359,54 @@ typedef struct #if CFG_TUD_AUDIO_ENABLE_EP_IN && (CFG_TUD_AUDIO_ENABLE_ENCODING || CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL) audio_format_type_t format_type_tx; uint8_t n_channels_tx; - uint8_t n_bytes_per_sampe_tx; + uint8_t n_bytes_per_sample_tx; #if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING audio_data_format_type_I_t format_type_I_tx; - uint8_t n_channels_per_ff_tx; uint8_t n_ff_used_tx; #endif #endif + /*------------- From this point, data is not cleared by bus reset -------------*/ + + // Buffer for control requests + uint8_t * ctrl_buf; + uint8_t ctrl_buf_sz; + + // Current active alternate settings + uint8_t * alt_setting; // We need to save the current alternate setting this way, because it is possible that there are AS interfaces which do not have an EP! + + // EP Transfer buffers and FIFOs +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING + tu_fifo_t ep_out_ff; +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING + tu_fifo_t ep_in_ff; +#endif + + // Audio control interrupt buffer - no FIFO - 6 Bytes according to UAC 2 specification (p. 74) +#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP + CFG_TUSB_MEM_ALIGN uint8_t ep_int_buf[6]; +#endif + // Support FIFOs for software encoding and decoding #if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING tu_fifo_t * rx_supp_ff; uint8_t n_rx_supp_ff; uint16_t rx_supp_ff_sz_max; +#if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING + uint8_t n_channels_per_ff_rx; +#endif #endif #if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING tu_fifo_t * tx_supp_ff; uint8_t n_tx_supp_ff; uint16_t tx_supp_ff_sz_max; +#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING + uint8_t n_channels_per_ff_tx; +#endif #endif // Linear buffer in case target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer is available or driver is would need to be changed dramatically OR the support FIFOs are used @@ -430,9 +433,146 @@ typedef struct #define ITF_MEM_RESET_SIZE offsetof(audiod_function_t, ctrl_buf) //--------------------------------------------------------------------+ +// WEAK FUNCTION STUBS +//--------------------------------------------------------------------+ + +#if CFG_TUD_AUDIO_ENABLE_EP_IN +TU_ATTR_WEAK bool tud_audio_tx_done_pre_load_cb(uint8_t rhport, uint8_t func_id, uint8_t ep_in, uint8_t cur_alt_setting) { + (void) rhport; + (void) func_id; + (void) ep_in; + (void) cur_alt_setting; + return true; +} + +TU_ATTR_WEAK bool tud_audio_tx_done_post_load_cb(uint8_t rhport, uint16_t n_bytes_copied, uint8_t func_id, uint8_t ep_in, uint8_t cur_alt_setting) { + (void) rhport; + (void) n_bytes_copied; + (void) func_id; + (void) ep_in; + (void) cur_alt_setting; + return true; +} +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT +TU_ATTR_WEAK bool tud_audio_rx_done_pre_read_cb(uint8_t rhport, uint16_t n_bytes_received, uint8_t func_id, uint8_t ep_out, uint8_t cur_alt_setting) { + (void) rhport; + (void) n_bytes_received; + (void) func_id; + (void) ep_out; + (void) cur_alt_setting; + return true; +} + +TU_ATTR_WEAK bool tud_audio_rx_done_post_read_cb(uint8_t rhport, uint16_t n_bytes_received, uint8_t func_id, uint8_t ep_out, uint8_t cur_alt_setting) { + (void) rhport; + (void) n_bytes_received; + (void) func_id; + (void) ep_out; + (void) cur_alt_setting; + return true; +} +#endif + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP +TU_ATTR_WEAK void tud_audio_fb_done_cb(uint8_t func_id) { + (void) func_id; +} + +TU_ATTR_WEAK void tud_audio_feedback_params_cb(uint8_t func_id, uint8_t alt_itf, audio_feedback_params_t* feedback_param) { + (void) func_id; + (void) alt_itf; + feedback_param->method = AUDIO_FEEDBACK_METHOD_DISABLED; +} + +TU_ATTR_WEAK bool tud_audio_feedback_format_correction_cb(uint8_t func_id) { + (void) func_id; + return CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION; +} +#endif + +TU_ATTR_WEAK TU_ATTR_FAST_FUNC void tud_audio_feedback_interval_isr(uint8_t func_id, uint32_t frame_number, uint8_t interval_shift) { + (void) func_id; + (void) frame_number; + (void) interval_shift; +} + +#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP +TU_ATTR_WEAK void tud_audio_int_done_cb(uint8_t rhport) { + (void) rhport; +} +#endif + +// Invoked when audio set interface request received +TU_ATTR_WEAK bool tud_audio_set_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request) { + (void) rhport; + (void) p_request; + return true; +} + +// Invoked when audio set interface request received which closes an EP +TU_ATTR_WEAK bool tud_audio_set_itf_close_EP_cb(uint8_t rhport, tusb_control_request_t const * p_request) { + (void) rhport; + (void) p_request; + return true; +} + +// Invoked when audio class specific set request received for an EP +TU_ATTR_WEAK bool tud_audio_set_req_ep_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff) { + (void) rhport; + (void) p_request; + (void) pBuff; + TU_LOG2(" No EP set request callback available!\r\n"); + return false; // In case no callback function is present or request can not be conducted we stall it +} + +// Invoked when audio class specific set request received for an interface +TU_ATTR_WEAK bool tud_audio_set_req_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff) { + (void) rhport; + (void) p_request; + (void) pBuff; + TU_LOG2(" No interface set request callback available!\r\n"); + return false; // In case no callback function is present or request can not be conducted we stall it +} + +// Invoked when audio class specific set request received for an entity +TU_ATTR_WEAK bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff) { + (void) rhport; + (void) p_request; + (void) pBuff; + TU_LOG2(" No entity set request callback available!\r\n"); + return false; // In case no callback function is present or request can not be conducted we stall it +} + +// Invoked when audio class specific get request received for an EP +TU_ATTR_WEAK bool tud_audio_get_req_ep_cb(uint8_t rhport, tusb_control_request_t const * p_request) { + (void) rhport; + (void) p_request; + TU_LOG2(" No EP get request callback available!\r\n"); + return false; // Stall +} + +// Invoked when audio class specific get request received for an interface +TU_ATTR_WEAK bool tud_audio_get_req_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request) { + (void) rhport; + (void) p_request; + TU_LOG2(" No interface get request callback available!\r\n"); + return false; // Stall +} + +// Invoked when audio class specific get request received for an entity +TU_ATTR_WEAK bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const * p_request) { + (void) rhport; + (void) p_request; + TU_LOG2(" No entity get request callback available!\r\n"); + return false; // Stall +} + +//--------------------------------------------------------------------+ // INTERNAL OBJECT & FUNCTION DECLARATION //--------------------------------------------------------------------+ -CFG_TUD_MEM_SECTION audiod_function_t _audiod_fct[CFG_TUD_AUDIO]; +tu_static CFG_TUD_MEM_SECTION audiod_function_t _audiod_fct[CFG_TUD_AUDIO]; #if CFG_TUD_AUDIO_ENABLE_EP_OUT static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t* audio, uint16_t n_bytes_received); @@ -475,7 +615,8 @@ static uint16_t audiod_tx_packet_size(const uint16_t* norminal_size, uint16_t da #endif #if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP -static bool set_fb_params_freq(audiod_function_t* audio, uint32_t sample_freq, uint32_t mclk_freq); +static bool audiod_set_fb_params_freq(audiod_function_t* audio, uint32_t sample_freq, uint32_t mclk_freq); +static void audiod_fb_fifo_count_update(audiod_function_t* audio, uint16_t lvl_new); #endif bool tud_audio_n_mounted(uint8_t func_id) @@ -556,19 +697,13 @@ static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t* audio, uint16_t uint8_t const *dummy2; uint8_t idx_audio_fct = 0; - if (tud_audio_rx_done_pre_read_cb || tud_audio_rx_done_post_read_cb) - { - idx_audio_fct = audiod_get_audio_fct_idx(audio); - TU_VERIFY(audiod_get_AS_interface_index(audio->ep_out_as_intf_num, audio, &idxItf, &dummy2)); - } + idx_audio_fct = audiod_get_audio_fct_idx(audio); + TU_VERIFY(audiod_get_AS_interface_index(audio->ep_out_as_intf_num, audio, &idxItf, &dummy2)); // Call a weak callback here - a possibility for user to get informed an audio packet was received and data gets now loaded into EP FIFO (or decoded into support RX software FIFO) - if (tud_audio_rx_done_pre_read_cb) - { - TU_VERIFY(tud_audio_rx_done_pre_read_cb(rhport, n_bytes_received, idx_audio_fct, audio->ep_out, audio->alt_setting[idxItf])); - } + TU_VERIFY(tud_audio_rx_done_pre_read_cb(rhport, n_bytes_received, idx_audio_fct, audio->ep_out, audio->alt_setting[idxItf])); -#if CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_EP_OUT +#if CFG_TUD_AUDIO_ENABLE_DECODING switch (audio->format_type_rx) { @@ -617,13 +752,17 @@ static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t* audio, uint16_t TU_VERIFY(usbd_edpt_xfer_fifo(rhport, audio->ep_out, &audio->ep_out_ff, audio->ep_out_sz), false); #endif +#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + if(audio->feedback.compute_method == AUDIO_FEEDBACK_METHOD_FIFO_COUNT) + { + audiod_fb_fifo_count_update(audio, tu_fifo_count(&audio->ep_out_ff)); + } +#endif + #endif // Call a weak callback here - a possibility for user to get informed decoding was completed - if (tud_audio_rx_done_post_read_cb) - { - TU_VERIFY(tud_audio_rx_done_post_read_cb(rhport, n_bytes_received, idx_audio_fct, audio->ep_out, audio->alt_setting[idxItf])); - } + TU_VERIFY(tud_audio_rx_done_post_read_cb(rhport, n_bytes_received, idx_audio_fct, audio->ep_out, audio->alt_setting[idxItf])); return true; } @@ -709,16 +848,16 @@ static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_function_t* audio, u if (info.len_lin != 0) { info.len_lin = tu_min16(nBytesPerFFToRead, info.len_lin); - src = &audio->lin_buf_out[cnt_ff*audio->n_channels_per_ff_rx * audio->n_bytes_per_sampe_rx]; + src = &audio->lin_buf_out[cnt_ff*audio->n_channels_per_ff_rx * audio->n_bytes_per_sample_rx]; dst_end = info.ptr_lin + info.len_lin; - src = audiod_interleaved_copy_bytes_fast_decode(audio->n_bytes_per_sampe_rx, info.ptr_lin, dst_end, src, n_ff_used); + src = audiod_interleaved_copy_bytes_fast_decode(audio->n_bytes_per_sample_rx, info.ptr_lin, dst_end, src, n_ff_used); // Handle wrapped part of FIFO info.len_wrap = tu_min16(nBytesPerFFToRead - info.len_lin, info.len_wrap); if (info.len_wrap != 0) { dst_end = info.ptr_wrap + info.len_wrap; - audiod_interleaved_copy_bytes_fast_decode(audio->n_bytes_per_sampe_rx, info.ptr_wrap, dst_end, src, n_ff_used); + audiod_interleaved_copy_bytes_fast_decode(audio->n_bytes_per_sample_rx, info.ptr_wrap, dst_end, src, n_ff_used); } tu_fifo_advance_write_pointer(&audio->rx_supp_ff[cnt_ff], info.len_lin + info.len_wrap); } @@ -727,6 +866,13 @@ static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_function_t* audio, u // Number of bytes should be a multiple of CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX * CFG_TUD_AUDIO_N_CHANNELS_RX but checking makes no sense - no way to correct it // TU_VERIFY(cnt != n_bytes); +#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + if(audio->feedback.compute_method == AUDIO_FEEDBACK_METHOD_FIFO_COUNT) + { + audiod_fb_fifo_count_update(audio, tu_fifo_count(&audio->rx_supp_ff[0])); + } +#endif + return true; } #endif //CFG_TUD_AUDIO_ENABLE_DECODING @@ -850,7 +996,7 @@ static bool audiod_tx_done_cb(uint8_t rhport, audiod_function_t * audio) // Call a weak callback here - a possibility for user to get informed former TX was completed and data gets now loaded into EP in buffer (in case FIFOs are used) or // if no FIFOs are used the user may use this call back to load its data into the EP IN buffer by use of tud_audio_n_write_ep_in_buffer(). - if (tud_audio_tx_done_pre_load_cb) TU_VERIFY(tud_audio_tx_done_pre_load_cb(rhport, idx_audio_fct, audio->ep_in, audio->alt_setting[idxItf])); + TU_VERIFY(tud_audio_tx_done_pre_load_cb(rhport, idx_audio_fct, audio->ep_in, audio->alt_setting[idxItf])); // Send everything in ISO EP FIFO uint16_t n_bytes_tx; @@ -913,7 +1059,7 @@ static bool audiod_tx_done_cb(uint8_t rhport, audiod_function_t * audio) #endif // Call a weak callback here - a possibility for user to get informed former TX was completed and how many bytes were loaded for the next frame - if (tud_audio_tx_done_post_load_cb) TU_VERIFY(tud_audio_tx_done_post_load_cb(rhport, n_bytes_tx, idx_audio_fct, audio->ep_in, audio->alt_setting[idxItf])); + TU_VERIFY(tud_audio_tx_done_post_load_cb(rhport, n_bytes_tx, idx_audio_fct, audio->ep_in, audio->alt_setting[idxItf])); return true; } @@ -1026,7 +1172,7 @@ static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audi // Limit to maximum sample number - THIS IS A POSSIBLE ERROR SOURCE IF TOO MANY SAMPLE WOULD NEED TO BE SENT BUT CAN NOT! nBytesPerFFToSend = tu_min16(nBytesPerFFToSend, audio->ep_in_sz / n_ff_used); // Round to full number of samples (flooring) - uint16_t const nSlotSize = audio->n_channels_per_ff_tx * audio->n_bytes_per_sampe_tx; + uint16_t const nSlotSize = audio->n_channels_per_ff_tx * audio->n_bytes_per_sample_tx; nBytesPerFFToSend = (nBytesPerFFToSend / nSlotSize) * nSlotSize; #endif @@ -1038,7 +1184,7 @@ static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audi for (cnt_ff = 0; cnt_ff < n_ff_used; cnt_ff++) { - dst = &audio->lin_buf_in[cnt_ff*audio->n_channels_per_ff_tx*audio->n_bytes_per_sampe_tx]; + dst = &audio->lin_buf_in[cnt_ff*audio->n_channels_per_ff_tx*audio->n_bytes_per_sample_tx]; tu_fifo_get_read_info(&audio->tx_supp_ff[cnt_ff], &info); @@ -1046,7 +1192,7 @@ static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audi { info.len_lin = tu_min16(nBytesPerFFToSend, info.len_lin); // Limit up to desired length src_end = (uint8_t *)info.ptr_lin + info.len_lin; - dst = audiod_interleaved_copy_bytes_fast_encode(audio->n_bytes_per_sampe_tx, info.ptr_lin, src_end, dst, n_ff_used); + dst = audiod_interleaved_copy_bytes_fast_encode(audio->n_bytes_per_sample_tx, info.ptr_lin, src_end, dst, n_ff_used); // Limit up to desired length info.len_wrap = tu_min16(nBytesPerFFToSend - info.len_lin, info.len_wrap); @@ -1055,7 +1201,7 @@ static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audi if (info.len_wrap != 0) { src_end = (uint8_t *)info.ptr_wrap + info.len_wrap; - audiod_interleaved_copy_bytes_fast_encode(audio->n_bytes_per_sampe_tx, info.ptr_wrap, src_end, dst, n_ff_used); + audiod_interleaved_copy_bytes_fast_encode(audio->n_bytes_per_sample_tx, info.ptr_wrap, src_end, dst, n_ff_used); } tu_fifo_advance_read_pointer(&audio->tx_supp_ff[cnt_ff], info.len_lin + info.len_wrap); @@ -1069,9 +1215,38 @@ static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audi // This function is called once a transmit of a feedback packet was successfully completed. Here, we get the next feedback value to be sent #if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP -static inline bool audiod_fb_send(uint8_t rhport, audiod_function_t *audio) +static inline bool audiod_fb_send(audiod_function_t *audio) { - return usbd_edpt_xfer(rhport, audio->ep_fb, (uint8_t *) &audio->feedback.value, 4); + bool apply_correction = (TUSB_SPEED_FULL == tud_speed_get()) && audio->feedback.format_correction; + // Format the feedback value + if (apply_correction) + { + uint8_t * fb = (uint8_t *) &audio->feedback.send_buf; + + // For FS format is 10.14 + *(fb++) = (audio->feedback.value >> 2) & 0xFF; + *(fb++) = (audio->feedback.value >> 10) & 0xFF; + *(fb++) = (audio->feedback.value >> 18) & 0xFF; + *fb = 0; + } else + { + audio->feedback.send_buf = audio->feedback.value; + } + + // About feedback format on FS + // + // 3 variables: Format | packetSize | sendSize | Working OS: + // 16.16 4 4 Linux, Windows + // 16.16 4 3 Linux + // 16.16 3 4 Linux + // 16.16 3 3 Linux + // 10.14 4 4 Linux + // 10.14 4 3 Linux + // 10.14 3 4 Linux, OSX + // 10.14 3 3 Linux, OSX + // + // We send 3 bytes since sending packet larger than wMaxPacketSize is pretty ugly + return usbd_edpt_xfer(audio->rhport, audio->ep_fb, (uint8_t *) &audio->feedback.send_buf, apply_correction ? 3 : 4); } #endif @@ -1492,7 +1667,8 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin #endif uint8_t const *p_desc = _audiod_fct[i].p_desc; uint8_t const *p_desc_end = p_desc + _audiod_fct[i].desc_length - TUD_AUDIO_DESC_IAD_LEN; - while (p_desc < p_desc_end) + // Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning + while (p_desc_end - p_desc > 0) { if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT) { @@ -1688,7 +1864,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * #endif // Invoke callback - can be used to stop data sampling - if (tud_audio_set_itf_close_EP_cb) TU_VERIFY(tud_audio_set_itf_close_EP_cb(rhport, p_request)); + TU_VERIFY(tud_audio_set_itf_close_EP_cb(rhport, p_request)); audio->ep_in = 0; // Necessary? @@ -1719,7 +1895,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * #endif // Invoke callback - can be used to stop data sampling - if (tud_audio_set_itf_close_EP_cb) TU_VERIFY(tud_audio_set_itf_close_EP_cb(rhport, p_request)); + TU_VERIFY(tud_audio_set_itf_close_EP_cb(rhport, p_request)); audio->ep_out = 0; // Necessary? @@ -1742,7 +1918,8 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * uint8_t const *p_desc_end = audio->p_desc + audio->desc_length - TUD_AUDIO_DESC_IAD_LEN; // p_desc starts at required interface with alternate setting zero - while (p_desc < p_desc_end) + // Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning + while (p_desc_end - p_desc > 0) { // Find correct interface if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const * )p_desc)->bInterfaceNumber == itf && ((tusb_desc_interface_t const * )p_desc)->bAlternateSetting == alt) @@ -1752,7 +1929,8 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * #endif // From this point forward follow the EP descriptors associated to the current alternate setting interface - Open EPs if necessary uint8_t foundEPs = 0, nEps = ((tusb_desc_interface_t const * )p_desc)->bNumEndpoints; - while (foundEPs < nEps && p_desc < p_desc_end) + // Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning + while (foundEPs < nEps && (p_desc_end - p_desc > 0)) { if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT) { @@ -1781,8 +1959,8 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * // Reconfigure size of support FIFOs - this is necessary to avoid samples to get split in case of a wrap #if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING - const uint16_t active_fifo_depth = (uint16_t) ((audio->tx_supp_ff_sz_max / (audio->n_channels_per_ff_tx * audio->n_bytes_per_sampe_tx)) - * (audio->n_channels_per_ff_tx * audio->n_bytes_per_sampe_tx)); + const uint16_t active_fifo_depth = (uint16_t) ((audio->tx_supp_ff_sz_max / (audio->n_channels_per_ff_tx * audio->n_bytes_per_sample_tx)) + * (audio->n_channels_per_ff_tx * audio->n_bytes_per_sample_tx)); for (uint8_t cnt = 0; cnt < audio->n_tx_supp_ff; cnt++) { tu_fifo_config(&audio->tx_supp_ff[cnt], audio->tx_supp_ff[cnt].buffer, active_fifo_depth, 1, true); @@ -1812,7 +1990,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * // Reconfigure size of support FIFOs - this is necessary to avoid samples to get split in case of a wrap #if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING - const uint16_t active_fifo_depth = (audio->rx_supp_ff_sz_max / audio->n_bytes_per_sampe_rx) * audio->n_bytes_per_sampe_rx; + const uint16_t active_fifo_depth = (audio->rx_supp_ff_sz_max / audio->n_bytes_per_sample_rx) * audio->n_bytes_per_sample_rx; for (uint8_t cnt = 0; cnt < audio->n_rx_supp_ff; cnt++) { tu_fifo_config(&audio->rx_supp_ff[cnt], audio->rx_supp_ff[cnt].buffer, active_fifo_depth, 1, true); @@ -1835,9 +2013,6 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * { audio->ep_fb = ep_addr; audio->feedback.frame_shift = desc_ep->bInterval -1; - - // Enable SOF interrupt if callback is implemented - if (tud_audio_feedback_interval_isr) usbd_sof_enable(rhport, SOF_CONSUMER_AUDIO, true); } #endif #endif // CFG_TUD_AUDIO_ENABLE_EP_OUT @@ -1850,20 +2025,23 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * TU_VERIFY(foundEPs == nEps); // Invoke one callback for a final set interface - if (tud_audio_set_itf_cb) TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request)); + TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request)); #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - // Prepare feedback computation if callback is available - if (tud_audio_feedback_params_cb) + // Prepare feedback computation if endpoint is available + if(audio->ep_fb != 0) { audio_feedback_params_t fb_param; tud_audio_feedback_params_cb(func_id, alt, &fb_param); audio->feedback.compute_method = fb_param.method; + if(TUSB_SPEED_FULL == tud_speed_get()) + audio->feedback.format_correction = tud_audio_feedback_format_correction_cb(func_id); + // Minimal/Maximum value in 16.16 format for full speed (1ms per frame) or high speed (125 us per frame) uint32_t const frame_div = (TUSB_SPEED_FULL == tud_speed_get()) ? 1000 : 8000; - audio->feedback.min_value = (fb_param.sample_freq/frame_div - 1) << 16; + audio->feedback.min_value = ((fb_param.sample_freq - 1)/frame_div) << 16; audio->feedback.max_value = (fb_param.sample_freq/frame_div + 1) << 16; switch(fb_param.method) @@ -1871,20 +2049,32 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * case AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED: case AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT: case AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2: - set_fb_params_freq(audio, fb_param.sample_freq, fb_param.frequency.mclk_freq); + audiod_set_fb_params_freq(audio, fb_param.sample_freq, fb_param.frequency.mclk_freq); break; - #if 0 // implement later case AUDIO_FEEDBACK_METHOD_FIFO_COUNT: { - uint64_t fb64 = ((uint64_t) fb_param.sample_freq) << 16; - audio->feedback.compute.fifo_count.nominal_value = (uint32_t) (fb64 / frame_div); - audio->feedback.compute.fifo_count.threshold_bytes = fb_param.fifo_count.threshold_bytes; - - tud_audio_fb_set(audio->feedback.compute.fifo_count.nominal_value); + // Initialize the threshold level to half filled + uint16_t fifo_lvl_thr; +#if CFG_TUD_AUDIO_ENABLE_DECODING + fifo_lvl_thr = tu_fifo_depth(&audio->rx_supp_ff[0]) / 2; +#else + fifo_lvl_thr = tu_fifo_depth(&audio->ep_out_ff) / 2; +#endif + audio->feedback.compute.fifo_count.fifo_lvl_thr = fifo_lvl_thr; + audio->feedback.compute.fifo_count.fifo_lvl_avg = ((uint32_t)fifo_lvl_thr) << 16; + // Avoid 64bit division + uint32_t nominal = ((fb_param.sample_freq / 100) << 16) / (frame_div / 100); + audio->feedback.compute.fifo_count.nom_value = nominal; + audio->feedback.compute.fifo_count.rate_const[0] = (audio->feedback.max_value - nominal) / fifo_lvl_thr; + audio->feedback.compute.fifo_count.rate_const[1] = (nominal - audio->feedback.min_value) / fifo_lvl_thr; + // On HS feedback is more sensitive since packet size can vary every MSOF, could cause instability + if(tud_speed_get() == TUSB_SPEED_HIGH) { + audio->feedback.compute.fifo_count.rate_const[0] /= 8; + audio->feedback.compute.fifo_count.rate_const[1] /= 8; + } } break; - #endif // nothing to do default: break; @@ -1902,16 +2092,19 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP // Disable SOF interrupt if no driver has any enabled feedback EP - bool disable = true; + bool enable_sof = false; for(uint8_t i=0; i < CFG_TUD_AUDIO; i++) { - if (_audiod_fct[i].ep_fb != 0) + if (_audiod_fct[i].ep_fb != 0 && + (_audiod_fct[i].feedback.compute_method == AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED || + _audiod_fct[i].feedback.compute_method == AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT || + _audiod_fct[i].feedback.compute_method == AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2 )) { - disable = false; + enable_sof = true; break; } } - if (disable) usbd_sof_enable(rhport, SOF_CONSUMER_AUDIO, false); + usbd_sof_enable(rhport, SOF_CONSUMER_AUDIO, enable_sof); #endif #if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL @@ -1941,35 +2134,19 @@ static bool audiod_control_complete(uint8_t rhport, tusb_control_request_t const if (entityID != 0) { - if (tud_audio_set_req_entity_cb) - { - // Check if entity is present and get corresponding driver index - TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id)); + // Check if entity is present and get corresponding driver index + TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id)); - // Invoke callback - return tud_audio_set_req_entity_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf); - } - else - { - TU_LOG2(" No entity set request callback available!\r\n"); - return false; // In case no callback function is present or request can not be conducted we stall it - } + // Invoke callback + return tud_audio_set_req_entity_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf); } else { - if (tud_audio_set_req_itf_cb) - { - // Find index of audio driver structure and verify interface really exists - TU_VERIFY(audiod_verify_itf_exists(itf, &func_id)); + // Find index of audio driver structure and verify interface really exists + TU_VERIFY(audiod_verify_itf_exists(itf, &func_id)); - // Invoke callback - return tud_audio_set_req_itf_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf); - } - else - { - TU_LOG2(" No interface set request callback available!\r\n"); - return false; // In case no callback function is present or request can not be conducted we stall it - } + // Invoke callback + return tud_audio_set_req_itf_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf); } } break; @@ -1978,19 +2155,11 @@ static bool audiod_control_complete(uint8_t rhport, tusb_control_request_t const { uint8_t ep = TU_U16_LOW(p_request->wIndex); - if (tud_audio_set_req_ep_cb) - { - // Check if entity is present and get corresponding driver index - TU_VERIFY(audiod_verify_ep_exists(ep, &func_id)); + // Check if entity is present and get corresponding driver index + TU_VERIFY(audiod_verify_ep_exists(ep, &func_id)); - // Invoke callback - return tud_audio_set_req_ep_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf); - } - else - { - TU_LOG2(" No EP set request callback available!\r\n"); - return false; // In case no callback function is present or request can not be conducted we stall it - } + // Invoke callback + return tud_audio_set_req_ep_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf); } break; // Unknown/Unsupported recipient @@ -2047,15 +2216,7 @@ static bool audiod_control_request(uint8_t rhport, tusb_control_request_t const // In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN) { - if (tud_audio_get_req_entity_cb) - { - return tud_audio_get_req_entity_cb(rhport, p_request); - } - else - { - TU_LOG2(" No entity get request callback available!\r\n"); - return false; // Stall - } + return tud_audio_get_req_entity_cb(rhport, p_request); } } else @@ -2066,15 +2227,7 @@ static bool audiod_control_request(uint8_t rhport, tusb_control_request_t const // In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN) { - if (tud_audio_get_req_itf_cb) - { - return tud_audio_get_req_itf_cb(rhport, p_request); - } - else - { - TU_LOG2(" No interface get request callback available!\r\n"); - return false; // Stall - } + return tud_audio_get_req_itf_cb(rhport, p_request); } } } @@ -2090,15 +2243,7 @@ static bool audiod_control_request(uint8_t rhport, tusb_control_request_t const // In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN) { - if (tud_audio_get_req_ep_cb) - { - return tud_audio_get_req_ep_cb(rhport, p_request); - } - else - { - TU_LOG2(" No EP get request callback available!\r\n"); - return false; // Stall - } + return tud_audio_get_req_ep_cb(rhport, p_request); } } break; @@ -2153,7 +2298,7 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3 // I assume here, that things above are handled by PHY // All transmission is done - what remains to do is to inform job was completed - if (tud_audio_int_done_cb) tud_audio_int_done_cb(rhport); + tud_audio_int_done_cb(rhport); return true; } @@ -2194,13 +2339,13 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3 // Transmission of feedback EP finished if (audio->ep_fb == ep_addr) { - if (tud_audio_fb_done_cb) tud_audio_fb_done_cb(func_id); + tud_audio_fb_done_cb(func_id); // Schedule a transmit with the new value if EP is not busy - if (!usbd_edpt_busy(rhport, audio->ep_fb)) + if (usbd_edpt_claim(rhport, audio->ep_fb)) { // Schedule next transmission - value is changed bytud_audio_n_fb_set() in the meantime or the old value gets sent - return audiod_fb_send(rhport, audio); + return audiod_fb_send(audio); } } #endif @@ -2212,7 +2357,7 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3 #if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP -static bool set_fb_params_freq(audiod_function_t* audio, uint32_t sample_freq, uint32_t mclk_freq) +static bool audiod_set_fb_params_freq(audiod_function_t* audio, uint32_t sample_freq, uint32_t mclk_freq) { // Check if frame interval is within sane limits // The interval value n_frames was taken from the descriptors within audiod_set_interface() @@ -2231,11 +2376,11 @@ static bool set_fb_params_freq(audiod_function_t* audio, uint32_t sample_freq, u if ((mclk_freq % sample_freq) == 0 && tu_is_power_of_two(mclk_freq / sample_freq)) { audio->feedback.compute_method = AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2; - audio->feedback.compute.power_of_2 = 16 - audio->feedback.frame_shift - tu_log2(mclk_freq / sample_freq); + audio->feedback.compute.power_of_2 = 16 - (audio->feedback.frame_shift - 1) - tu_log2(mclk_freq / sample_freq); } else if ( audio->feedback.compute_method == AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT) { - audio->feedback.compute.float_const = (float)sample_freq / mclk_freq * (1UL << (16 - audio->feedback.frame_shift)); + audio->feedback.compute.float_const = (float)sample_freq / mclk_freq * (1UL << (16 - (audio->feedback.frame_shift - 1))); } else { @@ -2246,6 +2391,38 @@ static bool set_fb_params_freq(audiod_function_t* audio, uint32_t sample_freq, u return true; } +static void audiod_fb_fifo_count_update(audiod_function_t* audio, uint16_t lvl_new) +{ + /* Low-pass (averaging) filter */ + uint32_t lvl = audio->feedback.compute.fifo_count.fifo_lvl_avg; + lvl = (uint32_t)(((uint64_t)lvl * 63 + ((uint32_t)lvl_new << 16)) >> 6); + audio->feedback.compute.fifo_count.fifo_lvl_avg = lvl; + + uint32_t const ff_lvl = lvl >> 16; + uint16_t const ff_thr = audio->feedback.compute.fifo_count.fifo_lvl_thr; + uint16_t const *rate = audio->feedback.compute.fifo_count.rate_const; + + uint32_t feedback; + + if(ff_lvl < ff_thr) + { + feedback = audio->feedback.compute.fifo_count.nom_value + (ff_thr - ff_lvl) * rate[0]; + } else + { + feedback = audio->feedback.compute.fifo_count.nom_value - (ff_lvl - ff_thr) * rate[1]; + } + + if ( feedback > audio->feedback.max_value ) feedback = audio->feedback.max_value; + if ( feedback < audio->feedback.min_value ) feedback = audio->feedback.min_value; + audio->feedback.value = feedback; + + // Schedule a transmit with the new value if EP is not busy - this triggers repetitive scheduling of the feedback value + if (usbd_edpt_claim(audio->rhport, audio->ep_fb)) + { + audiod_fb_send(audio); + } +} + uint32_t tud_audio_feedback_update(uint8_t func_id, uint32_t cycles) { audiod_function_t* audio = &_audiod_fct[func_id]; @@ -2263,7 +2440,7 @@ uint32_t tud_audio_feedback_update(uint8_t func_id, uint32_t cycles) case AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED: { - uint64_t fb64 = (((uint64_t) cycles) * audio->feedback.compute.fixed.sample_freq) << (16 - audio->feedback.frame_shift); + uint64_t fb64 = (((uint64_t) cycles) * audio->feedback.compute.fixed.sample_freq) << (16 - (audio->feedback.frame_shift - 1)); feedback = (uint32_t) (fb64 / audio->feedback.compute.fixed.mclk_freq); } break; @@ -2282,6 +2459,21 @@ uint32_t tud_audio_feedback_update(uint8_t func_id, uint32_t cycles) return feedback; } + +bool tud_audio_n_fb_set(uint8_t func_id, uint32_t feedback) +{ + TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); + + _audiod_fct[func_id].feedback.value = feedback; + + // Schedule a transmit with the new value if EP is not busy - this triggers repetitive scheduling of the feedback value + if (usbd_edpt_claim(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_fb)) + { + return audiod_fb_send(&_audiod_fct[func_id]); + } + + return true; +} #endif TU_ATTR_FAST_FUNC void audiod_sof_isr (uint8_t rhport, uint32_t frame_count) @@ -2308,7 +2500,7 @@ TU_ATTR_FAST_FUNC void audiod_sof_isr (uint8_t rhport, uint32_t frame_count) uint32_t const interval = 1UL << (audio->feedback.frame_shift - hs_adjust); if ( 0 == (frame_count & (interval-1)) ) { - if(tud_audio_feedback_interval_isr) tud_audio_feedback_interval_isr(i, frame_count, audio->feedback.frame_shift); + tud_audio_feedback_interval_isr(i, frame_count, audio->feedback.frame_shift); } } } @@ -2396,7 +2588,8 @@ static bool audiod_get_AS_interface_index(uint8_t itf, audiod_function_t * audio p_desc += ((audio_desc_cs_ac_interface_t const *)p_desc)->wTotalLength; uint8_t tmp = 0; - while (p_desc < p_desc_end) + // Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning + while (p_desc_end - p_desc > 0) { // We assume the number of alternate settings is increasing thus we return the index of alternate setting zero! if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const * )p_desc)->bAlternateSetting == 0) @@ -2449,7 +2642,8 @@ static bool audiod_verify_entity_exists(uint8_t itf, uint8_t entityID, uint8_t * uint8_t const *p_desc_end = ((audio_desc_cs_ac_interface_t const *)p_desc)->wTotalLength + p_desc; p_desc = tu_desc_next(p_desc); // Get past CS AC descriptor - while (p_desc < p_desc_end) + // Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning + while (p_desc_end - p_desc > 0) { if (p_desc[3] == entityID) // Entity IDs are always at offset 3 { @@ -2473,8 +2667,8 @@ static bool audiod_verify_itf_exists(uint8_t itf, uint8_t *func_id) // Get pointer at beginning and end uint8_t const *p_desc = _audiod_fct[i].p_desc; uint8_t const *p_desc_end = _audiod_fct[i].p_desc + _audiod_fct[i].desc_length - TUD_AUDIO_DESC_IAD_LEN; - - while (p_desc < p_desc_end) + // Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning + while (p_desc_end - p_desc > 0) { if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const *)_audiod_fct[i].p_desc)->bInterfaceNumber == itf) { @@ -2502,7 +2696,8 @@ static bool audiod_verify_ep_exists(uint8_t ep, uint8_t *func_id) uint8_t const *p_desc = tu_desc_next(_audiod_fct[i].p_desc); p_desc += ((audio_desc_cs_ac_interface_t const *)p_desc)->wTotalLength; - while (p_desc < p_desc_end) + // Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning + while (p_desc_end - p_desc > 0) { if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT && ((tusb_desc_endpoint_t const * )p_desc)->bEndpointAddress == ep) { @@ -2533,8 +2728,8 @@ static void audiod_parse_for_AS_params(audiod_function_t* audio, uint8_t const * #endif p_desc = tu_desc_next(p_desc); // Exclude standard AS interface descriptor of current alternate interface descriptor - - while (p_desc < p_desc_end) + // Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning + while (p_desc_end - p_desc > 0) { // Abort if follow up descriptor is a new standard interface descriptor - indicates the last AS descriptor was already finished if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE) break; @@ -2583,14 +2778,14 @@ static void audiod_parse_for_AS_params(audiod_function_t* audio, uint8_t const * #if CFG_TUD_AUDIO_ENABLE_EP_IN if (as_itf == audio->ep_in_as_intf_num) { - audio->n_bytes_per_sampe_tx = ((audio_desc_type_I_format_t const * )p_desc)->bSubslotSize; + audio->n_bytes_per_sample_tx = ((audio_desc_type_I_format_t const * )p_desc)->bSubslotSize; } #endif #if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING if (as_itf == audio->ep_out_as_intf_num) { - audio->n_bytes_per_sampe_rx = ((audio_desc_type_I_format_t const * )p_desc)->bSubslotSize; + audio->n_bytes_per_sample_rx = ((audio_desc_type_I_format_t const * )p_desc)->bSubslotSize; } #endif } @@ -2609,7 +2804,7 @@ static bool audiod_calc_tx_packet_sz(audiod_function_t* audio) { TU_VERIFY(audio->format_type_tx == AUDIO_FORMAT_TYPE_I); TU_VERIFY(audio->n_channels_tx); - TU_VERIFY(audio->n_bytes_per_sampe_tx); + TU_VERIFY(audio->n_bytes_per_sample_tx); TU_VERIFY(audio->interval_tx); TU_VERIFY(audio->sample_rate_tx); @@ -2618,9 +2813,9 @@ static bool audiod_calc_tx_packet_sz(audiod_function_t* audio) const uint16_t sample_normimal = (uint16_t)(audio->sample_rate_tx * interval / ((tud_speed_get() == TUSB_SPEED_FULL) ? 1000 : 8000)); const uint16_t sample_reminder = (uint16_t)(audio->sample_rate_tx * interval % ((tud_speed_get() == TUSB_SPEED_FULL) ? 1000 : 8000)); - const uint16_t packet_sz_tx_min = (uint16_t)((sample_normimal - 1) * audio->n_channels_tx * audio->n_bytes_per_sampe_tx); - const uint16_t packet_sz_tx_norm = (uint16_t)(sample_normimal * audio->n_channels_tx * audio->n_bytes_per_sampe_tx); - const uint16_t packet_sz_tx_max = (uint16_t)((sample_normimal + 1) * audio->n_channels_tx * audio->n_bytes_per_sampe_tx); + const uint16_t packet_sz_tx_min = (uint16_t)((sample_normimal - 1) * audio->n_channels_tx * audio->n_bytes_per_sample_tx); + const uint16_t packet_sz_tx_norm = (uint16_t)(sample_normimal * audio->n_channels_tx * audio->n_bytes_per_sample_tx); + const uint16_t packet_sz_tx_max = (uint16_t)((sample_normimal + 1) * audio->n_channels_tx * audio->n_bytes_per_sample_tx); // Endpoint size must larger than packet size TU_ASSERT(packet_sz_tx_max <= audio->ep_in_sz); @@ -2693,44 +2888,8 @@ static uint16_t audiod_tx_packet_size(const uint16_t* norminal_size, uint16_t da #endif -#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - -bool tud_audio_n_fb_set(uint8_t func_id, uint32_t feedback) -{ - TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); - - // Format the feedback value -#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION - if ( TUSB_SPEED_FULL == tud_speed_get() ) - { - uint8_t * fb = (uint8_t *) &_audiod_fct[func_id].feedback.value; - - // For FS format is 10.14 - *(fb++) = (feedback >> 2) & 0xFF; - *(fb++) = (feedback >> 10) & 0xFF; - *(fb++) = (feedback >> 18) & 0xFF; - // 4th byte is needed to work correctly with MS Windows - *fb = 0; - }else -#else - { - // Send value as-is, caller will choose the appropriate format - _audiod_fct[func_id].feedback.value = feedback; - } -#endif - - // Schedule a transmit with the new value if EP is not busy - this triggers repetitive scheduling of the feedback value - if (!usbd_edpt_busy(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_fb)) - { - return audiod_fb_send(_audiod_fct[func_id].rhport, &_audiod_fct[func_id]); - } - - return true; -} -#endif - // No security checks here - internal function only which should always succeed -uint8_t audiod_get_audio_fct_idx(audiod_function_t * audio) +static uint8_t audiod_get_audio_fct_idx(audiod_function_t * audio) { for (uint8_t cnt=0; cnt < CFG_TUD_AUDIO; cnt++) { diff --git a/src/class/audio/audio_device.h b/src/class/audio/audio_device.h index b16514fd4..ae253f49d 100644 --- a/src/class/audio/audio_device.h +++ b/src/class/audio/audio_device.h @@ -3,6 +3,7 @@ * * Copyright (c) 2020 Ha Thach (tinyusb.org) * Copyright (c) 2020 Reinhard Panhuber + * Copyright (c) 2023 HiFiPhile * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -192,6 +193,7 @@ #endif // Enable/disable conversion from 16.16 to 10.14 format on full-speed devices. See tud_audio_n_fb_set(). +// Can be override by tud_audio_feedback_format_correction_cb() #ifndef CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION #define CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION 0 // 0 or 1 #endif @@ -242,7 +244,8 @@ // Enable encoding/decodings - for these to work, support FIFOs need to be setup in appropriate numbers and size // The actual coding parameters of active AS alternate interface is parsed from the descriptors -// The item size of the FIFO is always fixed to one i.e. bytes! Furthermore, the actively used FIFO depth is reconfigured such that the depth is a multiple of the current sample size in order to avoid samples to get split up in case of a wrap in the FIFO ring buffer (depth = (max_depth / sampe_sz) * sampe_sz)! +// The item size of the FIFO is always fixed to one i.e. bytes! Furthermore, the actively used FIFO depth is reconfigured such that the depth is a multiple +// of the current sample size in order to avoid samples to get split up in case of a wrap in the FIFO ring buffer (depth = (max_depth / sample_sz) * sample_sz)! // This is important to remind in case you use DMAs! If the sample sizes changes, the DMA MUST BE RECONFIGURED just like the FIFOs for a different depth!!! // For PCM encoding/decoding @@ -446,63 +449,80 @@ static inline bool tud_audio_int_write (const audio_interru bool tud_audio_buffer_and_schedule_control_xfer(uint8_t rhport, tusb_control_request_t const * p_request, void* data, uint16_t len); //--------------------------------------------------------------------+ -// Application Callback API (weak is optional) +// Application Callback API //--------------------------------------------------------------------+ #if CFG_TUD_AUDIO_ENABLE_EP_IN -TU_ATTR_WEAK bool tud_audio_tx_done_pre_load_cb(uint8_t rhport, uint8_t func_id, uint8_t ep_in, uint8_t cur_alt_setting); -TU_ATTR_WEAK bool tud_audio_tx_done_post_load_cb(uint8_t rhport, uint16_t n_bytes_copied, uint8_t func_id, uint8_t ep_in, uint8_t cur_alt_setting); +bool tud_audio_tx_done_pre_load_cb(uint8_t rhport, uint8_t func_id, uint8_t ep_in, uint8_t cur_alt_setting); +bool tud_audio_tx_done_post_load_cb(uint8_t rhport, uint16_t n_bytes_copied, uint8_t func_id, uint8_t ep_in, uint8_t cur_alt_setting); #endif #if CFG_TUD_AUDIO_ENABLE_EP_OUT -TU_ATTR_WEAK bool tud_audio_rx_done_pre_read_cb(uint8_t rhport, uint16_t n_bytes_received, uint8_t func_id, uint8_t ep_out, uint8_t cur_alt_setting); -TU_ATTR_WEAK bool tud_audio_rx_done_post_read_cb(uint8_t rhport, uint16_t n_bytes_received, uint8_t func_id, uint8_t ep_out, uint8_t cur_alt_setting); +bool tud_audio_rx_done_pre_read_cb(uint8_t rhport, uint16_t n_bytes_received, uint8_t func_id, uint8_t ep_out, uint8_t cur_alt_setting); +bool tud_audio_rx_done_post_read_cb(uint8_t rhport, uint16_t n_bytes_received, uint8_t func_id, uint8_t ep_out, uint8_t cur_alt_setting); #endif #if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP -TU_ATTR_WEAK void tud_audio_fb_done_cb(uint8_t func_id); +void tud_audio_fb_done_cb(uint8_t func_id); -// determined by the user itself and set by use of tud_audio_n_fb_set(). The feedback value may be determined e.g. from some fill status of some FIFO buffer. Advantage: No ISR interrupt is enabled, hence the CPU need not to handle an ISR every 1ms or 125us and thus less CPU load, disadvantage: typically a larger FIFO is needed to compensate for jitter (e.g. 8 frames), i.e. a larger delay is introduced. - -// Feedback value is calculated within the audio driver by use of SOF interrupt. The driver needs information about the master clock f_m from which the audio sample frequency f_s is derived, f_s itself, and the cycle count of f_m at time of the SOF interrupt (e.g. by use of a hardware counter) - see tud_audio_set_fb_params(). Advantage: Reduced jitter in the feedback value computation, hence, the receive FIFO can be smaller (e.g. 2 frames) and thus a smaller delay is possible, disadvantage: higher CPU load due to SOF ISR handling every frame i.e. 1ms or 125us. This option is a great starting point to try the SOF ISR option but depending on your hardware setup (performance of the CPU) it might not work. If so, figure out why and use the next option. (The most critical point is the reading of the cycle counter value of f_m. It is read from within the SOF ISR - see: audiod_sof() -, hence, the ISR must has a high priority such that no software dependent "random" delay i.e. jitter is introduced). +// Note about feedback calculation +// +// Option 1 - AUDIO_FEEDBACK_METHOD_FIFO_COUNT +// Feedback value is calculated within the audio driver by regulating the FIFO level to half fill. +// Advantage: No ISR interrupt is enabled, hence the CPU need not to handle an ISR every 1ms or 125us and thus less CPU load, well tested +// (Windows, Linux, OSX) with a reliable result so far. +// Disadvantage: A FIFO of minimal 4 frames is needed to compensate for jitter, an average delay of 2 frames is introduced. +// +// Option 2 - AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED / AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT +// Feedback value is calculated within the audio driver by use of SOF interrupt. The driver needs information about the master clock f_m from +// which the audio sample frequency f_s is derived, f_s itself, and the cycle count of f_m at time of the SOF interrupt (e.g. by use of a hardware counter). +// See tud_audio_set_fb_params() and tud_audio_feedback_update() +// Advantage: Reduced jitter in the feedback value computation, hence, the receive FIFO can be smaller and thus a smaller delay is possible. +// Disadvantage: higher CPU load due to SOF ISR handling every frame i.e. 1ms or 125us. (The most critical point is the reading of the cycle counter value of f_m. +// It is read from within the SOF ISR - see: audiod_sof() -, hence, the ISR must has a high priority such that no software dependent "random" delay i.e. jitter is introduced). +// Long-term drift could occur since error is accumulated. +// +// Option 3 - manual +// Determined by the user itself and set by use of tud_audio_n_fb_set(). The feedback value may be determined e.g. from some fill status of some FIFO buffer. +// Advantage: No ISR interrupt is enabled, hence the CPU need not to handle an ISR every 1ms or 125us and thus less CPU load. +// Disadvantage: typically a larger FIFO is needed to compensate for jitter (e.g. 6 frames), i.e. a larger delay is introduced. -// Feedback value is determined by the user by use of SOF interrupt. The user may use tud_audio_sof_isr() which is called every SOF (of course only invoked when an alternate interface other than zero was set). The number of frames used to determine the feedback value for the currently active alternate setting can be get by tud_audio_get_fb_n_frames(). The feedback value must be set by use of tud_audio_n_fb_set(). // This function is used to provide data rate feedback from an asynchronous sink. Feedback value will be sent at FB endpoint interval till it's changed. // // The feedback format is specified to be 16.16 for HS and 10.14 for FS devices (see Universal Serial Bus Specification Revision 2.0 5.12.4.2). By default, -// the choice of format is left to the caller and feedback argument is sent as-is. If CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION is set, then tinyusb -// expects 16.16 format and handles the conversion to 10.14 on FS. +// the choice of format is left to the caller and feedback argument is sent as-is. If CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION is set or tud_audio_feedback_format_correction_cb() +// return true, then tinyusb expects 16.16 format and handles the conversion to 10.14 on FS. +// +// Note that due to a bug in its USB Audio 2.0 driver, Windows currently requires 16.16 format for _all_ USB 2.0 devices. On Linux and it seems the +// driver can work with either format. // -// Note that due to a bug in its USB Audio 2.0 driver, Windows currently requires 16.16 format for _all_ USB 2.0 devices. On Linux and macOS it seems the -// driver can work with either format. So a good compromise is to keep format correction disabled and stick to 16.16 format. - // Feedback value can be determined from within the SOF ISR of the audio driver. This should reduce jitter. If the feature is used, the user can not set the feedback value. - +// // Determine feedback value - The feedback method is described in 5.12.4.2 of the USB 2.0 spec // Boiled down, the feedback value Ff = n_samples / (micro)frame. -// Since an accuracy of less than 1 Sample / second is desired, at least n_frames = ceil(2^K * f_s / f_m) frames need to be measured, where K = 10 for full speed and K = 13 for high speed, f_s is the sampling frequency e.g. 48 kHz and f_m is the cpu clock frequency e.g. 100 MHz (or any other master clock whose clock count is available and locked to f_s) +// Since an accuracy of less than 1 Sample / second is desired, at least n_frames = ceil(2^K * f_s / f_m) frames need to be measured, where K = 10 for full speed and K = 13 +// for high speed, f_s is the sampling frequency e.g. 48 kHz and f_m is the cpu clock frequency e.g. 100 MHz (or any other master clock whose clock count is available and locked to f_s) // The update interval in the (4.10.2.1) Feedback Endpoint Descriptor must be less or equal to 2^(K - P), where P = min( ceil(log2(f_m / f_s)), K) // feedback = n_cycles / n_frames * f_s / f_m in 16.16 format, where n_cycles are the number of main clock cycles within fb_n_frames - bool tud_audio_n_fb_set(uint8_t func_id, uint32_t feedback); -static inline bool tud_audio_fb_set(uint32_t feedback); -// Update feedback value with passed cycles since last time this update function is called. +// Update feedback value with passed MCLK cycles since last time this update function is called. // Typically called within tud_audio_sof_isr(). Required tud_audio_feedback_params_cb() is implemented // This function will also call tud_audio_feedback_set() // return feedback value in 16.16 for reference (0 for error) +// Example : +// binterval=3 (4ms); FS = 48kHz; MCLK = 12.288MHz +// In 4 SOF MCLK counted 49152 cycles uint32_t tud_audio_feedback_update(uint8_t func_id, uint32_t cycles); enum { AUDIO_FEEDBACK_METHOD_DISABLED, AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED, AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT, - AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2, - - // impelemnt later - // AUDIO_FEEDBACK_METHOD_FIFO_COUNT + AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2, // For driver internal use only + AUDIO_FEEDBACK_METHOD_FIFO_COUNT }; typedef struct { @@ -514,52 +534,50 @@ typedef struct { uint32_t mclk_freq; // Main clock frequency in Hz i.e. master clock to which sample clock is based on }frequency; -#if 0 // implement later - struct { - uint32_t threshold_bytes; // minimum number of bytes received to be considered as filled/ready - }fifo_count; -#endif }; }audio_feedback_params_t; // Invoked when needed to set feedback parameters -TU_ATTR_WEAK void tud_audio_feedback_params_cb(uint8_t func_id, uint8_t alt_itf, audio_feedback_params_t* feedback_param); +void tud_audio_feedback_params_cb(uint8_t func_id, uint8_t alt_itf, audio_feedback_params_t* feedback_param); // Callback in ISR context, invoked periodically according to feedback endpoint bInterval. // Could be used to compute and update feedback value, should be placed in RAM if possible // frame_number : current SOF count // interval_shift: number of bit shift i.e log2(interval) from Feedback endpoint descriptor -TU_ATTR_WEAK TU_ATTR_FAST_FUNC void tud_audio_feedback_interval_isr(uint8_t func_id, uint32_t frame_number, uint8_t interval_shift); +TU_ATTR_FAST_FUNC void tud_audio_feedback_interval_isr(uint8_t func_id, uint32_t frame_number, uint8_t interval_shift); +// (Full-Speed only) Callback to set feedback format correction is applied or not, +// default to CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION if not implemented. +bool tud_audio_feedback_format_correction_cb(uint8_t func_id); #endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP #if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP -TU_ATTR_WEAK void tud_audio_int_done_cb(uint8_t rhport); +void tud_audio_int_done_cb(uint8_t rhport); #endif // Invoked when audio set interface request received -TU_ATTR_WEAK bool tud_audio_set_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request); +bool tud_audio_set_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request); // Invoked when audio set interface request received which closes an EP -TU_ATTR_WEAK bool tud_audio_set_itf_close_EP_cb(uint8_t rhport, tusb_control_request_t const * p_request); +bool tud_audio_set_itf_close_EP_cb(uint8_t rhport, tusb_control_request_t const * p_request); // Invoked when audio class specific set request received for an EP -TU_ATTR_WEAK bool tud_audio_set_req_ep_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff); +bool tud_audio_set_req_ep_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff); // Invoked when audio class specific set request received for an interface -TU_ATTR_WEAK bool tud_audio_set_req_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff); +bool tud_audio_set_req_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff); // Invoked when audio class specific set request received for an entity -TU_ATTR_WEAK bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff); +bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff); // Invoked when audio class specific get request received for an EP -TU_ATTR_WEAK bool tud_audio_get_req_ep_cb(uint8_t rhport, tusb_control_request_t const * p_request); +bool tud_audio_get_req_ep_cb(uint8_t rhport, tusb_control_request_t const * p_request); // Invoked when audio class specific get request received for an interface -TU_ATTR_WEAK bool tud_audio_get_req_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request); +bool tud_audio_get_req_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request); // Invoked when audio class specific get request received for an entity -TU_ATTR_WEAK bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const * p_request); +bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const * p_request); //--------------------------------------------------------------------+ // Inline Functions diff --git a/src/class/bth/bth_device.c b/src/class/bth/bth_device.c index cbf6e1332..a79908627 100755 --- a/src/class/bth/bth_device.c +++ b/src/class/bth/bth_device.c @@ -42,10 +42,14 @@ typedef struct uint8_t itf_num; uint8_t ep_ev; uint8_t ep_acl_in; + uint16_t ep_acl_in_pkt_sz; uint8_t ep_acl_out; uint8_t ep_voice[2]; // Not used yet uint8_t ep_voice_size[2][CFG_TUD_BTH_ISO_ALT_COUNT]; + // Previous amount of bytes sent when issuing ZLP + uint32_t prev_xferred_bytes; + // Endpoint Transfer buffer CFG_TUSB_MEM_ALIGN bt_hci_cmd_t hci_cmd; CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_BTH_DATA_EPSIZE]; @@ -127,11 +131,25 @@ uint16_t btd_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_ TU_ASSERT(usbd_edpt_open(rhport, desc_ep), 0); _btd_itf.ep_ev = desc_ep->bEndpointAddress; + desc_ep = (tusb_desc_endpoint_t const *)tu_desc_next(desc_ep); + // Open endpoint pair - TU_ASSERT(usbd_open_edpt_pair(rhport, tu_desc_next(desc_ep), 2, TUSB_XFER_BULK, &_btd_itf.ep_acl_out, - &_btd_itf.ep_acl_in), 0); + TU_ASSERT(usbd_open_edpt_pair(rhport, (uint8_t const *)desc_ep, 2, + TUSB_XFER_BULK, &_btd_itf.ep_acl_out, + &_btd_itf.ep_acl_in), + 0); + + // Save acl in endpoint max packet size + tusb_desc_endpoint_t const *desc_ep_acl_in = desc_ep; + for (size_t p = 0; p < 2; p++) { + if (tu_edpt_dir(desc_ep_acl_in->bEndpointAddress) == TUSB_DIR_IN) { + _btd_itf.ep_acl_in_pkt_sz = tu_edpt_packet_size(desc_ep_acl_in); + break; + } + desc_ep_acl_in = (tusb_desc_endpoint_t const *)tu_desc_next(desc_ep_acl_in); + } - itf_desc = (tusb_desc_interface_t const *)tu_desc_next(tu_desc_next(tu_desc_next(desc_ep))); + itf_desc = (tusb_desc_interface_t const *)tu_desc_next(tu_desc_next(desc_ep)); // Prepare for incoming data from host TU_ASSERT(usbd_edpt_xfer(rhport, _btd_itf.ep_acl_out, _btd_itf.epout_buf, CFG_TUD_BTH_DATA_EPSIZE), 0); @@ -238,10 +256,8 @@ bool btd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t c return true; } -bool btd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) -{ - (void)result; - +bool btd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, + uint32_t xferred_bytes) { // received new data from host if (ep_addr == _btd_itf.ep_acl_out) { @@ -256,7 +272,20 @@ bool btd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t } else if (ep_addr == _btd_itf.ep_acl_in) { - if (tud_bt_acl_data_sent_cb) tud_bt_acl_data_sent_cb((uint16_t)xferred_bytes); + if ((result == XFER_RESULT_SUCCESS) && (xferred_bytes > 0) && + ((xferred_bytes & (_btd_itf.ep_acl_in_pkt_sz - 1)) == 0)) { + // Save number of transferred bytes + _btd_itf.prev_xferred_bytes = xferred_bytes; + + // Send zero-length packet + tud_bt_acl_data_send(NULL, 0); + } else if (tud_bt_acl_data_sent_cb) { + if (xferred_bytes == 0) { + xferred_bytes = _btd_itf.prev_xferred_bytes; + _btd_itf.prev_xferred_bytes = 0; + } + tud_bt_acl_data_sent_cb((uint16_t)xferred_bytes); + } } return true; diff --git a/src/class/cdc/cdc_device.c b/src/class/cdc/cdc_device.c index f36725eba..ebc408f5a 100644 --- a/src/class/cdc/cdc_device.c +++ b/src/class/cdc/cdc_device.c @@ -45,8 +45,7 @@ //--------------------------------------------------------------------+ #define BULK_PACKET_SIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) -typedef struct -{ +typedef struct { uint8_t itf_num; uint8_t ep_notif; uint8_t ep_in; @@ -56,7 +55,7 @@ typedef struct uint8_t line_state; /*------------- From this point, data is not cleared by bus reset -------------*/ - char wanted_char; + char wanted_char; TU_ATTR_ALIGNED(4) cdc_line_coding_t line_coding; // FIFO @@ -72,19 +71,22 @@ typedef struct // Endpoint Transfer buffer CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_CDC_EP_BUFSIZE]; CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_CDC_EP_BUFSIZE]; - -}cdcd_interface_t; +} cdcd_interface_t; #define ITF_MEM_RESET_SIZE offsetof(cdcd_interface_t, wanted_char) //--------------------------------------------------------------------+ // INTERNAL OBJECT & FUNCTION DECLARATION //--------------------------------------------------------------------+ -CFG_TUD_MEM_SECTION tu_static cdcd_interface_t _cdcd_itf[CFG_TUD_CDC]; +CFG_TUD_MEM_SECTION static cdcd_interface_t _cdcd_itf[CFG_TUD_CDC]; +static tud_cdc_configure_fifo_t _cdcd_fifo_cfg; -static bool _prep_out_transaction (cdcd_interface_t* p_cdc) -{ +static bool _prep_out_transaction (cdcd_interface_t* p_cdc) { uint8_t const rhport = 0; + + // Skip if usb is not ready yet + TU_VERIFY(tud_ready() && p_cdc->ep_out); + uint16_t available = tu_fifo_remaining(&p_cdc->rx_ff); // Prepare for incoming data but only allow what we can store in the ring buffer. @@ -99,14 +101,11 @@ static bool _prep_out_transaction (cdcd_interface_t* p_cdc) // fifo can be changed before endpoint is claimed available = tu_fifo_remaining(&p_cdc->rx_ff); - if ( available >= sizeof(p_cdc->epout_buf) ) - { + if ( available >= sizeof(p_cdc->epout_buf) ) { return usbd_edpt_xfer(rhport, p_cdc->ep_out, p_cdc->epout_buf, sizeof(p_cdc->epout_buf)); - }else - { + }else { // Release endpoint since we don't make any transfer usbd_edpt_release(rhport, p_cdc->ep_out); - return false; } } @@ -114,51 +113,53 @@ static bool _prep_out_transaction (cdcd_interface_t* p_cdc) //--------------------------------------------------------------------+ // APPLICATION API //--------------------------------------------------------------------+ -bool tud_cdc_n_connected(uint8_t itf) -{ + +bool tud_cdc_configure_fifo(tud_cdc_configure_fifo_t const* cfg) { + TU_VERIFY(cfg); + _cdcd_fifo_cfg = (*cfg); + return true; +} + +bool tud_cdc_n_ready(uint8_t itf) { + return tud_ready() && _cdcd_itf[itf].ep_in != 0 && _cdcd_itf[itf].ep_out != 0; +} + +bool tud_cdc_n_connected(uint8_t itf) { // DTR (bit 0) active is considered as connected return tud_ready() && tu_bit_test(_cdcd_itf[itf].line_state, 0); } -uint8_t tud_cdc_n_get_line_state (uint8_t itf) -{ +uint8_t tud_cdc_n_get_line_state(uint8_t itf) { return _cdcd_itf[itf].line_state; } -void tud_cdc_n_get_line_coding (uint8_t itf, cdc_line_coding_t* coding) -{ +void tud_cdc_n_get_line_coding(uint8_t itf, cdc_line_coding_t* coding) { (*coding) = _cdcd_itf[itf].line_coding; } -void tud_cdc_n_set_wanted_char (uint8_t itf, char wanted) -{ +void tud_cdc_n_set_wanted_char(uint8_t itf, char wanted) { _cdcd_itf[itf].wanted_char = wanted; } - //--------------------------------------------------------------------+ // READ API //--------------------------------------------------------------------+ -uint32_t tud_cdc_n_available(uint8_t itf) -{ +uint32_t tud_cdc_n_available(uint8_t itf) { return tu_fifo_count(&_cdcd_itf[itf].rx_ff); } -uint32_t tud_cdc_n_read(uint8_t itf, void* buffer, uint32_t bufsize) -{ +uint32_t tud_cdc_n_read(uint8_t itf, void* buffer, uint32_t bufsize) { cdcd_interface_t* p_cdc = &_cdcd_itf[itf]; uint32_t num_read = tu_fifo_read_n(&p_cdc->rx_ff, buffer, (uint16_t) TU_MIN(bufsize, UINT16_MAX)); _prep_out_transaction(p_cdc); return num_read; } -bool tud_cdc_n_peek(uint8_t itf, uint8_t* chr) -{ +bool tud_cdc_n_peek(uint8_t itf, uint8_t* chr) { return tu_fifo_peek(&_cdcd_itf[itf].rx_ff, chr); } -void tud_cdc_n_read_flush (uint8_t itf) -{ +void tud_cdc_n_read_flush(uint8_t itf) { cdcd_interface_t* p_cdc = &_cdcd_itf[itf]; tu_fifo_clear(&p_cdc->rx_ff); _prep_out_transaction(p_cdc); @@ -167,16 +168,15 @@ void tud_cdc_n_read_flush (uint8_t itf) //--------------------------------------------------------------------+ // WRITE API //--------------------------------------------------------------------+ -uint32_t tud_cdc_n_write(uint8_t itf, void const* buffer, uint32_t bufsize) -{ +uint32_t tud_cdc_n_write(uint8_t itf, void const* buffer, uint32_t bufsize) { cdcd_interface_t* p_cdc = &_cdcd_itf[itf]; uint16_t ret = tu_fifo_write_n(&p_cdc->tx_ff, buffer, (uint16_t) TU_MIN(bufsize, UINT16_MAX)); // flush if queue more than packet size - if ( tu_fifo_count(&p_cdc->tx_ff) >= BULK_PACKET_SIZE - #if CFG_TUD_CDC_TX_BUFSIZE < BULK_PACKET_SIZE - || tu_fifo_full(&p_cdc->tx_ff) // check full if fifo size is less than packet size - #endif + if (tu_fifo_count(&p_cdc->tx_ff) >= BULK_PACKET_SIZE + #if CFG_TUD_CDC_TX_BUFSIZE < BULK_PACKET_SIZE + || tu_fifo_full(&p_cdc->tx_ff) // check full if fifo size is less than packet size + #endif ) { tud_cdc_n_write_flush(itf); } @@ -184,30 +184,27 @@ uint32_t tud_cdc_n_write(uint8_t itf, void const* buffer, uint32_t bufsize) return ret; } -uint32_t tud_cdc_n_write_flush (uint8_t itf) -{ +uint32_t tud_cdc_n_write_flush(uint8_t itf) { cdcd_interface_t* p_cdc = &_cdcd_itf[itf]; // Skip if usb is not ready yet - TU_VERIFY( tud_ready(), 0 ); + TU_VERIFY(tud_ready(), 0); // No data to send - if ( !tu_fifo_count(&p_cdc->tx_ff) ) return 0; + if (!tu_fifo_count(&p_cdc->tx_ff)) return 0; uint8_t const rhport = 0; // Claim the endpoint - TU_VERIFY( usbd_edpt_claim(rhport, p_cdc->ep_in), 0 ); + TU_VERIFY(usbd_edpt_claim(rhport, p_cdc->ep_in), 0); // Pull data from FIFO uint16_t const count = tu_fifo_read_n(&p_cdc->tx_ff, p_cdc->epin_buf, sizeof(p_cdc->epin_buf)); - if ( count ) - { - TU_ASSERT( usbd_edpt_xfer(rhport, p_cdc->ep_in, p_cdc->epin_buf, count), 0 ); + if (count) { + TU_ASSERT(usbd_edpt_xfer(rhport, p_cdc->ep_in, p_cdc->epin_buf, count), 0); return count; - }else - { + } else { // Release endpoint since we don't make any transfer // Note: data is dropped if terminal is not connected usbd_edpt_release(rhport, p_cdc->ep_in); @@ -215,33 +212,30 @@ uint32_t tud_cdc_n_write_flush (uint8_t itf) } } -uint32_t tud_cdc_n_write_available (uint8_t itf) -{ +uint32_t tud_cdc_n_write_available(uint8_t itf) { return tu_fifo_remaining(&_cdcd_itf[itf].tx_ff); } -bool tud_cdc_n_write_clear (uint8_t itf) -{ +bool tud_cdc_n_write_clear(uint8_t itf) { return tu_fifo_clear(&_cdcd_itf[itf].tx_ff); } //--------------------------------------------------------------------+ // USBD Driver API //--------------------------------------------------------------------+ -void cdcd_init(void) -{ +void cdcd_init(void) { tu_memclr(_cdcd_itf, sizeof(_cdcd_itf)); + tu_memclr(&_cdcd_fifo_cfg, sizeof(_cdcd_fifo_cfg)); - for(uint8_t i=0; i<CFG_TUD_CDC; i++) - { + for (uint8_t i = 0; i < CFG_TUD_CDC; i++) { cdcd_interface_t* p_cdc = &_cdcd_itf[i]; p_cdc->wanted_char = (char) -1; // default line coding is : stop bit = 1, parity = none, data bits = 8 - p_cdc->line_coding.bit_rate = 115200; + p_cdc->line_coding.bit_rate = 115200; p_cdc->line_coding.stop_bits = 0; - p_cdc->line_coding.parity = 0; + p_cdc->line_coding.parity = 0; p_cdc->line_coding.data_bits = 8; // Config RX fifo @@ -285,35 +279,28 @@ bool cdcd_deinit(void) { return true; } -void cdcd_reset(uint8_t rhport) -{ +void cdcd_reset(uint8_t rhport) { (void) rhport; - for(uint8_t i=0; i<CFG_TUD_CDC; i++) - { + for (uint8_t i = 0; i < CFG_TUD_CDC; i++) { cdcd_interface_t* p_cdc = &_cdcd_itf[i]; tu_memclr(p_cdc, ITF_MEM_RESET_SIZE); - tu_fifo_clear(&p_cdc->rx_ff); - #if !CFG_TUD_CDC_PERSISTENT_TX_BUFF - tu_fifo_clear(&p_cdc->tx_ff); - #endif + if (!_cdcd_fifo_cfg.rx_persistent) tu_fifo_clear(&p_cdc->rx_ff); + if (!_cdcd_fifo_cfg.tx_persistent) tu_fifo_clear(&p_cdc->tx_ff); tu_fifo_set_overwritable(&p_cdc->tx_ff, true); } } -uint16_t cdcd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len) -{ +uint16_t cdcd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len) { // Only support ACM subclass TU_VERIFY( TUSB_CLASS_CDC == itf_desc->bInterfaceClass && CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass, 0); // Find available interface - cdcd_interface_t * p_cdc = NULL; - for(uint8_t cdc_id=0; cdc_id<CFG_TUD_CDC; cdc_id++) - { - if ( _cdcd_itf[cdc_id].ep_in == 0 ) - { + cdcd_interface_t* p_cdc = NULL; + for (uint8_t cdc_id = 0; cdc_id < CFG_TUD_CDC; cdc_id++) { + if (_cdcd_itf[cdc_id].ep_in == 0) { p_cdc = &_cdcd_itf[cdc_id]; break; } @@ -324,39 +311,36 @@ uint16_t cdcd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint1 p_cdc->itf_num = itf_desc->bInterfaceNumber; uint16_t drv_len = sizeof(tusb_desc_interface_t); - uint8_t const * p_desc = tu_desc_next( itf_desc ); + uint8_t const* p_desc = tu_desc_next(itf_desc); // Communication Functional Descriptors - while ( TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) && drv_len <= max_len ) - { + while (TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) && drv_len <= max_len) { drv_len += tu_desc_len(p_desc); - p_desc = tu_desc_next(p_desc); + p_desc = tu_desc_next(p_desc); } - if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) ) - { + if (TUSB_DESC_ENDPOINT == tu_desc_type(p_desc)) { // notification endpoint - tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc; + tusb_desc_endpoint_t const* desc_ep = (tusb_desc_endpoint_t const*) p_desc; - TU_ASSERT( usbd_edpt_open(rhport, desc_ep), 0 ); + TU_ASSERT(usbd_edpt_open(rhport, desc_ep), 0); p_cdc->ep_notif = desc_ep->bEndpointAddress; drv_len += tu_desc_len(p_desc); - p_desc = tu_desc_next(p_desc); + p_desc = tu_desc_next(p_desc); } //------------- Data Interface (if any) -------------// - if ( (TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) && - (TUSB_CLASS_CDC_DATA == ((tusb_desc_interface_t const *) p_desc)->bInterfaceClass) ) - { + if ((TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) && + (TUSB_CLASS_CDC_DATA == ((tusb_desc_interface_t const*) p_desc)->bInterfaceClass)) { // next to endpoint descriptor drv_len += tu_desc_len(p_desc); - p_desc = tu_desc_next(p_desc); + p_desc = tu_desc_next(p_desc); // Open endpoint pair - TU_ASSERT( usbd_open_edpt_pair(rhport, p_desc, 2, TUSB_XFER_BULK, &p_cdc->ep_out, &p_cdc->ep_in), 0 ); + TU_ASSERT(usbd_open_edpt_pair(rhport, p_desc, 2, TUSB_XFER_BULK, &p_cdc->ep_out, &p_cdc->ep_in), 0); - drv_len += 2*sizeof(tusb_desc_endpoint_t); + drv_len += 2 * sizeof(tusb_desc_endpoint_t); } // Prepare for incoming data @@ -368,8 +352,7 @@ uint16_t cdcd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint1 // Invoked when a control transfer occurred on an interface of this class // Driver response accordingly to the request and the transfer stage (setup/data/ack) // return false to stall control endpoint (e.g unsupported request) -bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) -{ +bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const* request) { // Handle class request only TU_VERIFY(request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS); @@ -377,42 +360,33 @@ bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t cdcd_interface_t* p_cdc = _cdcd_itf; // Identify which interface to use - for ( ; ; itf++, p_cdc++) - { + for (;; itf++, p_cdc++) { if (itf >= TU_ARRAY_SIZE(_cdcd_itf)) return false; - if ( p_cdc->itf_num == request->wIndex ) break; + if (p_cdc->itf_num == request->wIndex) break; } - switch ( request->bRequest ) - { + switch (request->bRequest) { case CDC_REQUEST_SET_LINE_CODING: - if (stage == CONTROL_STAGE_SETUP) - { + if (stage == CONTROL_STAGE_SETUP) { TU_LOG_DRV(" Set Line Coding\r\n"); tud_control_xfer(rhport, request, &p_cdc->line_coding, sizeof(cdc_line_coding_t)); + } else if (stage == CONTROL_STAGE_ACK) { + if (tud_cdc_line_coding_cb) tud_cdc_line_coding_cb(itf, &p_cdc->line_coding); } - else if ( stage == CONTROL_STAGE_ACK) - { - if ( tud_cdc_line_coding_cb ) tud_cdc_line_coding_cb(itf, &p_cdc->line_coding); - } - break; + break; case CDC_REQUEST_GET_LINE_CODING: - if (stage == CONTROL_STAGE_SETUP) - { + if (stage == CONTROL_STAGE_SETUP) { TU_LOG_DRV(" Get Line Coding\r\n"); tud_control_xfer(rhport, request, &p_cdc->line_coding, sizeof(cdc_line_coding_t)); } - break; + break; case CDC_REQUEST_SET_CONTROL_LINE_STATE: - if (stage == CONTROL_STAGE_SETUP) - { + if (stage == CONTROL_STAGE_SETUP) { tud_control_status(rhport, request); - } - else if (stage == CONTROL_STAGE_ACK) - { + } else if (stage == CONTROL_STAGE_ACK) { // CDC PSTN v1.2 section 6.3.12 // Bit 0: Indicates if DTE is present or not. // This signal corresponds to V.24 signal 108/2 and RS-232 signal DTR (Data Terminal Ready) @@ -429,61 +403,54 @@ bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t TU_LOG_DRV(" Set Control Line State: DTR = %d, RTS = %d\r\n", dtr, rts); // Invoke callback - if ( tud_cdc_line_state_cb ) tud_cdc_line_state_cb(itf, dtr, rts); + if (tud_cdc_line_state_cb) tud_cdc_line_state_cb(itf, dtr, rts); } - break; + break; + case CDC_REQUEST_SEND_BREAK: - if (stage == CONTROL_STAGE_SETUP) - { + if (stage == CONTROL_STAGE_SETUP) { tud_control_status(rhport, request); - } - else if (stage == CONTROL_STAGE_ACK) - { + } else if (stage == CONTROL_STAGE_ACK) { TU_LOG_DRV(" Send Break\r\n"); - if ( tud_cdc_send_break_cb ) tud_cdc_send_break_cb(itf, request->wValue); + if (tud_cdc_send_break_cb) tud_cdc_send_break_cb(itf, request->wValue); } - break; + break; - default: return false; // stall unsupported request + default: + return false; // stall unsupported request } return true; } -bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) -{ +bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) { (void) result; uint8_t itf; cdcd_interface_t* p_cdc; // Identify which interface to use - for (itf = 0; itf < CFG_TUD_CDC; itf++) - { + for (itf = 0; itf < CFG_TUD_CDC; itf++) { p_cdc = &_cdcd_itf[itf]; - if ( ( ep_addr == p_cdc->ep_out ) || ( ep_addr == p_cdc->ep_in ) ) break; + if ((ep_addr == p_cdc->ep_out) || (ep_addr == p_cdc->ep_in)) break; } TU_ASSERT(itf < CFG_TUD_CDC); // Received new data - if ( ep_addr == p_cdc->ep_out ) - { + if (ep_addr == p_cdc->ep_out) { tu_fifo_write_n(&p_cdc->rx_ff, p_cdc->epout_buf, (uint16_t) xferred_bytes); // Check for wanted char and invoke callback if needed - if ( tud_cdc_rx_wanted_cb && (((signed char) p_cdc->wanted_char) != -1) ) - { - for ( uint32_t i = 0; i < xferred_bytes; i++ ) - { - if ( (p_cdc->wanted_char == p_cdc->epout_buf[i]) && !tu_fifo_empty(&p_cdc->rx_ff) ) - { + if (tud_cdc_rx_wanted_cb && (((signed char) p_cdc->wanted_char) != -1)) { + for (uint32_t i = 0; i < xferred_bytes; i++) { + if ((p_cdc->wanted_char == p_cdc->epout_buf[i]) && !tu_fifo_empty(&p_cdc->rx_ff)) { tud_cdc_rx_wanted_cb(itf, p_cdc->wanted_char); } } } // invoke receive callback (if there is still data) - if (tud_cdc_rx_cb && !tu_fifo_empty(&p_cdc->rx_ff) ) tud_cdc_rx_cb(itf); + if (tud_cdc_rx_cb && !tu_fifo_empty(&p_cdc->rx_ff)) tud_cdc_rx_cb(itf); // prepare for OUT transaction _prep_out_transaction(p_cdc); @@ -492,19 +459,15 @@ bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_ // Data sent to host, we continue to fetch from tx fifo to send. // Note: This will cause incorrect baudrate set in line coding. // Though maybe the baudrate is not really important !!! - if ( ep_addr == p_cdc->ep_in ) - { + if (ep_addr == p_cdc->ep_in) { // invoke transmit callback to possibly refill tx fifo - if ( tud_cdc_tx_complete_cb ) tud_cdc_tx_complete_cb(itf); + if (tud_cdc_tx_complete_cb) tud_cdc_tx_complete_cb(itf); - if ( 0 == tud_cdc_n_write_flush(itf) ) - { + if (0 == tud_cdc_n_write_flush(itf)) { // If there is no data left, a ZLP should be sent if // xferred_bytes is multiple of EP Packet size and not zero - if ( !tu_fifo_count(&p_cdc->tx_ff) && xferred_bytes && (0 == (xferred_bytes & (BULK_PACKET_SIZE-1))) ) - { - if ( usbd_edpt_claim(rhport, p_cdc->ep_in) ) - { + if (!tu_fifo_count(&p_cdc->tx_ff) && xferred_bytes && (0 == (xferred_bytes & (BULK_PACKET_SIZE - 1)))) { + if (usbd_edpt_claim(rhport, p_cdc->ep_in)) { usbd_edpt_xfer(rhport, p_cdc->ep_in, NULL, 0); } } diff --git a/src/class/cdc/cdc_device.h b/src/class/cdc/cdc_device.h index db709b3bc..3ad7c8baf 100644 --- a/src/class/cdc/cdc_device.h +++ b/src/class/cdc/cdc_device.h @@ -24,8 +24,8 @@ * This file is part of the TinyUSB stack. */ -#ifndef _TUSB_CDC_DEVICE_H_ -#define _TUSB_CDC_DEVICE_H_ +#ifndef TUSB_CDC_DEVICE_H_ +#define TUSB_CDC_DEVICE_H_ #include "cdc.h" @@ -41,213 +41,170 @@ #define CFG_TUD_CDC_EP_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) #endif -// By default the TX fifo buffer is cleared on connect / bus reset. -// Enable this to persist any data in the fifo instead. -#ifndef CFG_TUD_CDC_PERSISTENT_TX_BUFF - #define CFG_TUD_CDC_PERSISTENT_TX_BUFF (0) -#endif - #ifdef __cplusplus extern "C" { #endif -/** \addtogroup CDC_Serial Serial - * @{ - * \defgroup CDC_Serial_Device Device - * @{ */ +//--------------------------------------------------------------------+ +// Driver Configuration +//--------------------------------------------------------------------+ + +typedef struct TU_ATTR_PACKED { + uint8_t rx_persistent : 1; // keep rx fifo on bus reset or disconnect + uint8_t tx_persistent : 1; // keep tx fifo on bus reset or disconnect +} tud_cdc_configure_fifo_t; + +// Configure CDC FIFOs behavior +bool tud_cdc_configure_fifo(tud_cdc_configure_fifo_t const* cfg); //--------------------------------------------------------------------+ -// Application API (Multiple Ports) -// CFG_TUD_CDC > 1 +// Application API (Multiple Ports) i.e. CFG_TUD_CDC > 1 //--------------------------------------------------------------------+ +// Check if interface is ready +bool tud_cdc_n_ready(uint8_t itf); + // Check if terminal is connected to this port -bool tud_cdc_n_connected (uint8_t itf); +bool tud_cdc_n_connected(uint8_t itf); // Get current line state. Bit 0: DTR (Data Terminal Ready), Bit 1: RTS (Request to Send) -uint8_t tud_cdc_n_get_line_state (uint8_t itf); +uint8_t tud_cdc_n_get_line_state(uint8_t itf); // Get current line encoding: bit rate, stop bits parity etc .. -void tud_cdc_n_get_line_coding (uint8_t itf, cdc_line_coding_t* coding); +void tud_cdc_n_get_line_coding(uint8_t itf, cdc_line_coding_t* coding); // Set special character that will trigger tud_cdc_rx_wanted_cb() callback on receiving -void tud_cdc_n_set_wanted_char (uint8_t itf, char wanted); +void tud_cdc_n_set_wanted_char(uint8_t itf, char wanted); // Get the number of bytes available for reading -uint32_t tud_cdc_n_available (uint8_t itf); +uint32_t tud_cdc_n_available(uint8_t itf); // Read received bytes -uint32_t tud_cdc_n_read (uint8_t itf, void* buffer, uint32_t bufsize); +uint32_t tud_cdc_n_read(uint8_t itf, void* buffer, uint32_t bufsize); // Read a byte, return -1 if there is none -static inline -int32_t tud_cdc_n_read_char (uint8_t itf); +TU_ATTR_ALWAYS_INLINE static inline int32_t tud_cdc_n_read_char(uint8_t itf) { + uint8_t ch; + return tud_cdc_n_read(itf, &ch, 1) ? (int32_t) ch : -1; +} // Clear the received FIFO -void tud_cdc_n_read_flush (uint8_t itf); +void tud_cdc_n_read_flush(uint8_t itf); // Get a byte from FIFO without removing it -bool tud_cdc_n_peek (uint8_t itf, uint8_t* ui8); +bool tud_cdc_n_peek(uint8_t itf, uint8_t* ui8); // Write bytes to TX FIFO, data may remain in the FIFO for a while -uint32_t tud_cdc_n_write (uint8_t itf, void const* buffer, uint32_t bufsize); +uint32_t tud_cdc_n_write(uint8_t itf, void const* buffer, uint32_t bufsize); // Write a byte -static inline -uint32_t tud_cdc_n_write_char (uint8_t itf, char ch); +TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_cdc_n_write_char(uint8_t itf, char ch) { + return tud_cdc_n_write(itf, &ch, 1); +} // Write a null-terminated string -static inline -uint32_t tud_cdc_n_write_str (uint8_t itf, char const* str); +TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_cdc_n_write_str(uint8_t itf, char const* str) { + return tud_cdc_n_write(itf, str, strlen(str)); +} // Force sending data if possible, return number of forced bytes -uint32_t tud_cdc_n_write_flush (uint8_t itf); +uint32_t tud_cdc_n_write_flush(uint8_t itf); // Return the number of bytes (characters) available for writing to TX FIFO buffer in a single n_write operation. -uint32_t tud_cdc_n_write_available (uint8_t itf); +uint32_t tud_cdc_n_write_available(uint8_t itf); // Clear the transmit FIFO -bool tud_cdc_n_write_clear (uint8_t itf); +bool tud_cdc_n_write_clear(uint8_t itf); //--------------------------------------------------------------------+ // Application API (Single Port) //--------------------------------------------------------------------+ -static inline bool tud_cdc_connected (void); -static inline uint8_t tud_cdc_get_line_state (void); -static inline void tud_cdc_get_line_coding (cdc_line_coding_t* coding); -static inline void tud_cdc_set_wanted_char (char wanted); - -static inline uint32_t tud_cdc_available (void); -static inline int32_t tud_cdc_read_char (void); -static inline uint32_t tud_cdc_read (void* buffer, uint32_t bufsize); -static inline void tud_cdc_read_flush (void); -static inline bool tud_cdc_peek (uint8_t* ui8); - -static inline uint32_t tud_cdc_write_char (char ch); -static inline uint32_t tud_cdc_write (void const* buffer, uint32_t bufsize); -static inline uint32_t tud_cdc_write_str (char const* str); -static inline uint32_t tud_cdc_write_flush (void); -static inline uint32_t tud_cdc_write_available (void); -static inline bool tud_cdc_write_clear (void); - -//--------------------------------------------------------------------+ -// Application Callback API (weak is optional) -//--------------------------------------------------------------------+ - -// Invoked when received new data -TU_ATTR_WEAK void tud_cdc_rx_cb(uint8_t itf); - -// Invoked when received `wanted_char` -TU_ATTR_WEAK void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char); - -// Invoked when a TX is complete and therefore space becomes available in TX buffer -TU_ATTR_WEAK void tud_cdc_tx_complete_cb(uint8_t itf); - -// Invoked when line state DTR & RTS are changed via SET_CONTROL_LINE_STATE -TU_ATTR_WEAK void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts); - -// Invoked when line coding is change via SET_LINE_CODING -TU_ATTR_WEAK void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* p_line_coding); -// Invoked when received send break -TU_ATTR_WEAK void tud_cdc_send_break_cb(uint8_t itf, uint16_t duration_ms); - -//--------------------------------------------------------------------+ -// Inline Functions -//--------------------------------------------------------------------+ -static inline int32_t tud_cdc_n_read_char (uint8_t itf) -{ - uint8_t ch; - return tud_cdc_n_read(itf, &ch, 1) ? (int32_t) ch : -1; +TU_ATTR_ALWAYS_INLINE static inline bool tud_cdc_ready(void) { + return tud_cdc_n_ready(0); } -static inline uint32_t tud_cdc_n_write_char(uint8_t itf, char ch) -{ - return tud_cdc_n_write(itf, &ch, 1); -} - -static inline uint32_t tud_cdc_n_write_str (uint8_t itf, char const* str) -{ - return tud_cdc_n_write(itf, str, strlen(str)); -} - -static inline bool tud_cdc_connected (void) -{ +TU_ATTR_ALWAYS_INLINE static inline bool tud_cdc_connected(void) { return tud_cdc_n_connected(0); } -static inline uint8_t tud_cdc_get_line_state (void) -{ +TU_ATTR_ALWAYS_INLINE static inline uint8_t tud_cdc_get_line_state(void) { return tud_cdc_n_get_line_state(0); } -static inline void tud_cdc_get_line_coding (cdc_line_coding_t* coding) -{ +TU_ATTR_ALWAYS_INLINE static inline void tud_cdc_get_line_coding(cdc_line_coding_t* coding) { tud_cdc_n_get_line_coding(0, coding); } -static inline void tud_cdc_set_wanted_char (char wanted) -{ +TU_ATTR_ALWAYS_INLINE static inline void tud_cdc_set_wanted_char(char wanted) { tud_cdc_n_set_wanted_char(0, wanted); } -static inline uint32_t tud_cdc_available (void) -{ +TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_cdc_available(void) { return tud_cdc_n_available(0); } -static inline int32_t tud_cdc_read_char (void) -{ +TU_ATTR_ALWAYS_INLINE static inline int32_t tud_cdc_read_char(void) { return tud_cdc_n_read_char(0); } -static inline uint32_t tud_cdc_read (void* buffer, uint32_t bufsize) -{ +TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_cdc_read(void* buffer, uint32_t bufsize) { return tud_cdc_n_read(0, buffer, bufsize); } -static inline void tud_cdc_read_flush (void) -{ +TU_ATTR_ALWAYS_INLINE static inline void tud_cdc_read_flush(void) { tud_cdc_n_read_flush(0); } -static inline bool tud_cdc_peek (uint8_t* ui8) -{ +TU_ATTR_ALWAYS_INLINE static inline bool tud_cdc_peek(uint8_t* ui8) { return tud_cdc_n_peek(0, ui8); } -static inline uint32_t tud_cdc_write_char (char ch) -{ +TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_cdc_write_char(char ch) { return tud_cdc_n_write_char(0, ch); } -static inline uint32_t tud_cdc_write (void const* buffer, uint32_t bufsize) -{ +TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_cdc_write(void const* buffer, uint32_t bufsize) { return tud_cdc_n_write(0, buffer, bufsize); } -static inline uint32_t tud_cdc_write_str (char const* str) -{ +TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_cdc_write_str(char const* str) { return tud_cdc_n_write_str(0, str); } -static inline uint32_t tud_cdc_write_flush (void) -{ +TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_cdc_write_flush(void) { return tud_cdc_n_write_flush(0); } -static inline uint32_t tud_cdc_write_available(void) -{ +TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_cdc_write_available(void) { return tud_cdc_n_write_available(0); } -static inline bool tud_cdc_write_clear(void) -{ +TU_ATTR_ALWAYS_INLINE static inline bool tud_cdc_write_clear(void) { return tud_cdc_n_write_clear(0); } -/** @} */ -/** @} */ +//--------------------------------------------------------------------+ +// Application Callback API (weak is optional) +//--------------------------------------------------------------------+ + +// Invoked when received new data +TU_ATTR_WEAK void tud_cdc_rx_cb(uint8_t itf); + +// Invoked when received `wanted_char` +TU_ATTR_WEAK void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char); + +// Invoked when a TX is complete and therefore space becomes available in TX buffer +TU_ATTR_WEAK void tud_cdc_tx_complete_cb(uint8_t itf); + +// Invoked when line state DTR & RTS are changed via SET_CONTROL_LINE_STATE +TU_ATTR_WEAK void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts); + +// Invoked when line coding is change via SET_LINE_CODING +TU_ATTR_WEAK void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* p_line_coding); + +// Invoked when received send break +TU_ATTR_WEAK void tud_cdc_send_break_cb(uint8_t itf, uint16_t duration_ms); //--------------------------------------------------------------------+ // INTERNAL USBD-CLASS DRIVER API diff --git a/src/class/hid/hid_device.c b/src/class/hid/hid_device.c index ada01582e..ef6c7f3af 100644 --- a/src/class/hid/hid_device.c +++ b/src/class/hid/hid_device.c @@ -46,43 +46,68 @@ typedef struct { uint8_t itf_protocol; // Boot mouse or keyboard uint16_t report_desc_len; - CFG_TUSB_MEM_ALIGN uint8_t protocol_mode; // Boot (0) or Report protocol (1) - CFG_TUSB_MEM_ALIGN uint8_t idle_rate; // up to application to handle idle rate - - CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_HID_EP_BUFSIZE]; - CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_HID_EP_BUFSIZE]; - CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf[CFG_TUD_HID_EP_BUFSIZE]; + uint8_t protocol_mode; // Boot (0) or Report protocol (1) + uint8_t idle_rate; // up to application to handle idle rate // TODO save hid descriptor since host can specifically request this after enumeration // Note: HID descriptor may be not available from application after enumeration tusb_hid_descriptor_hid_t const *hid_descriptor; + + uint8_t ctrl_buf[CFG_TUD_HID_EP_BUFSIZE]; + CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_HID_EP_BUFSIZE]; + CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_HID_EP_BUFSIZE]; } hidd_interface_t; CFG_TUD_MEM_SECTION tu_static hidd_interface_t _hidd_itf[CFG_TUD_HID]; /*------------- Helpers -------------*/ -static inline uint8_t get_index_by_itfnum(uint8_t itf_num) -{ +TU_ATTR_ALWAYS_INLINE static inline uint8_t get_index_by_itfnum(uint8_t itf_num) { for (uint8_t i = 0; i < CFG_TUD_HID; i++) { - if (itf_num == _hidd_itf[i].itf_num) + if (itf_num == _hidd_itf[i].itf_num) { return i; + } } - return 0xFF; } //--------------------------------------------------------------------+ +// Weak stubs: invoked if no strong implementation is available +//--------------------------------------------------------------------+ +TU_ATTR_WEAK void tud_hid_set_protocol_cb(uint8_t instance, uint8_t protocol) { + (void) instance; + (void) protocol; +} + +TU_ATTR_WEAK bool tud_hid_set_idle_cb(uint8_t instance, uint8_t idle_rate) { + (void) instance; + (void) idle_rate; + return true; +} + +TU_ATTR_WEAK void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, uint16_t len) { + (void) instance; + (void) report; + (void) len; +} + +// Invoked when a transfer wasn't successful +TU_ATTR_WEAK void tud_hid_report_failed_cb(uint8_t instance, hid_report_type_t report_type, uint8_t const* report, uint16_t xferred_bytes) { + (void) instance; + (void) report_type; + (void) report; + (void) xferred_bytes; +} + +//--------------------------------------------------------------------+ // APPLICATION API //--------------------------------------------------------------------+ -bool tud_hid_n_ready(uint8_t instance) -{ +bool tud_hid_n_ready(uint8_t instance) { uint8_t const rhport = 0; uint8_t const ep_in = _hidd_itf[instance].ep_in; return tud_ready() && (ep_in != 0) && !usbd_edpt_busy(rhport, ep_in); } -bool tud_hid_n_report(uint8_t instance, uint8_t report_id, void const *report, uint16_t len) -{ +bool tud_hid_n_report(uint8_t instance, uint8_t report_id, void const *report, uint16_t len) { uint8_t const rhport = 0; hidd_interface_t *p_hid = &_hidd_itf[instance]; @@ -101,14 +126,16 @@ bool tud_hid_n_report(uint8_t instance, uint8_t report_id, void const *report, u return usbd_edpt_xfer(rhport, p_hid->ep_in, p_hid->epin_buf, len); } -uint8_t tud_hid_n_interface_protocol(uint8_t instance) { return _hidd_itf[instance].itf_protocol; } +uint8_t tud_hid_n_interface_protocol(uint8_t instance) { + return _hidd_itf[instance].itf_protocol; +} -uint8_t tud_hid_n_get_protocol(uint8_t instance) { return _hidd_itf[instance].protocol_mode; } +uint8_t tud_hid_n_get_protocol(uint8_t instance) { + return _hidd_itf[instance].protocol_mode; +} -bool tud_hid_n_keyboard_report(uint8_t instance, uint8_t report_id, uint8_t modifier, uint8_t keycode[6]) -{ +bool tud_hid_n_keyboard_report(uint8_t instance, uint8_t report_id, uint8_t modifier, const uint8_t keycode[6]) { hid_keyboard_report_t report; - report.modifier = modifier; report.reserved = 0; @@ -121,8 +148,8 @@ bool tud_hid_n_keyboard_report(uint8_t instance, uint8_t report_id, uint8_t modi return tud_hid_n_report(instance, report_id, &report, sizeof(report)); } -bool tud_hid_n_mouse_report(uint8_t instance, uint8_t report_id, uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal) -{ +bool tud_hid_n_mouse_report(uint8_t instance, uint8_t report_id, + uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal) { hid_mouse_report_t report = { .buttons = buttons, .x = x, @@ -134,8 +161,8 @@ bool tud_hid_n_mouse_report(uint8_t instance, uint8_t report_id, uint8_t buttons return tud_hid_n_report(instance, report_id, &report, sizeof(report)); } -bool tud_hid_n_abs_mouse_report(uint8_t instance, uint8_t report_id, uint8_t buttons, int16_t x, int16_t y, int8_t vertical, int8_t horizontal) -{ +bool tud_hid_n_abs_mouse_report(uint8_t instance, uint8_t report_id, + uint8_t buttons, int16_t x, int16_t y, int8_t vertical, int8_t horizontal) { hid_abs_mouse_report_t report = { .buttons = buttons, .x = x, @@ -146,8 +173,8 @@ bool tud_hid_n_abs_mouse_report(uint8_t instance, uint8_t report_id, uint8_t but return tud_hid_n_report(instance, report_id, &report, sizeof(report)); } -bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id, int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons) -{ +bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id, + int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons) { hid_gamepad_report_t report = { .x = x, .y = y, @@ -165,28 +192,25 @@ bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id, int8_t x, int //--------------------------------------------------------------------+ // USBD-CLASS API //--------------------------------------------------------------------+ -void hidd_init(void) -{ +void hidd_init(void) { hidd_reset(0); } -bool hidd_deinit(void) -{ +bool hidd_deinit(void) { return true; } -void hidd_reset(uint8_t rhport) -{ +void hidd_reset(uint8_t rhport) { (void)rhport; tu_memclr(_hidd_itf, sizeof(_hidd_itf)); } -uint16_t hidd_open(uint8_t rhport, tusb_desc_interface_t const *desc_itf, uint16_t max_len) -{ +uint16_t hidd_open(uint8_t rhport, tusb_desc_interface_t const *desc_itf, uint16_t max_len) { TU_VERIFY(TUSB_CLASS_HID == desc_itf->bInterfaceClass, 0); // len = interface + hid + n*endpoints - uint16_t const drv_len = (uint16_t)(sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) + desc_itf->bNumEndpoints * sizeof(tusb_desc_endpoint_t)); + uint16_t const drv_len = (uint16_t) (sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) + + desc_itf->bNumEndpoints * sizeof(tusb_desc_endpoint_t)); TU_ASSERT(max_len >= drv_len, 0); // Find available interface @@ -211,8 +235,9 @@ uint16_t hidd_open(uint8_t rhport, tusb_desc_interface_t const *desc_itf, uint16 p_desc = tu_desc_next(p_desc); TU_ASSERT(usbd_open_edpt_pair(rhport, p_desc, desc_itf->bNumEndpoints, TUSB_XFER_INTERRUPT, &p_hid->ep_out, &p_hid->ep_in), 0); - if (desc_itf->bInterfaceSubClass == HID_SUBCLASS_BOOT) + if (desc_itf->bInterfaceSubClass == HID_SUBCLASS_BOOT) { p_hid->itf_protocol = desc_itf->bInterfaceProtocol; + } p_hid->protocol_mode = HID_PROTOCOL_REPORT; // Per Specs: default is report mode p_hid->itf_num = desc_itf->bInterfaceNumber; @@ -234,8 +259,7 @@ uint16_t hidd_open(uint8_t rhport, tusb_desc_interface_t const *desc_itf, uint16 // Invoked when a control transfer occurred on an interface of this class // Driver response accordingly to the request and the transfer stage (setup/data/ack) // return false to stall control endpoint (e.g unsupported request) -bool hidd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) -{ +bool hidd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) { TU_VERIFY(request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE); uint8_t const hid_itf = get_index_by_itfnum((uint8_t)request->wIndex); @@ -262,90 +286,82 @@ bool hidd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t } else if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS) { //------------- Class Specific Request -------------// switch (request->bRequest) { - case HID_REQ_CONTROL_GET_REPORT: - if (stage == CONTROL_STAGE_SETUP) { - uint8_t const report_type = tu_u16_high(request->wValue); - uint8_t const report_id = tu_u16_low(request->wValue); + case HID_REQ_CONTROL_GET_REPORT: + if (stage == CONTROL_STAGE_SETUP) { + uint8_t const report_type = tu_u16_high(request->wValue); + uint8_t const report_id = tu_u16_low(request->wValue); - uint8_t *report_buf = p_hid->ctrl_buf; - uint16_t req_len = tu_min16(request->wLength, CFG_TUD_HID_EP_BUFSIZE); + uint8_t* report_buf = p_hid->ctrl_buf; + uint16_t req_len = tu_min16(request->wLength, CFG_TUD_HID_EP_BUFSIZE); + uint16_t xferlen = 0; - uint16_t xferlen = 0; + // If host request a specific Report ID, add ID to as 1 byte of response + if ((report_id != HID_REPORT_TYPE_INVALID) && (req_len > 1)) { + *report_buf++ = report_id; + req_len--; + xferlen++; + } - // If host request a specific Report ID, add ID to as 1 byte of response - if ((report_id != HID_REPORT_TYPE_INVALID) && (req_len > 1)) { - *report_buf++ = report_id; - req_len--; + xferlen += tud_hid_get_report_cb(hid_itf, report_id, (hid_report_type_t) report_type, report_buf, req_len); + TU_ASSERT(xferlen > 0); - xferlen++; + tud_control_xfer(rhport, request, p_hid->ctrl_buf, xferlen); } + break; - xferlen += tud_hid_get_report_cb(hid_itf, report_id, (hid_report_type_t)report_type, report_buf, req_len); - TU_ASSERT(xferlen > 0); - - tud_control_xfer(rhport, request, p_hid->ctrl_buf, xferlen); - } - break; + case HID_REQ_CONTROL_SET_REPORT: + if (stage == CONTROL_STAGE_SETUP) { + TU_VERIFY(request->wLength <= sizeof(p_hid->ctrl_buf)); + tud_control_xfer(rhport, request, p_hid->ctrl_buf, request->wLength); + } else if (stage == CONTROL_STAGE_ACK) { + uint8_t const report_type = tu_u16_high(request->wValue); + uint8_t const report_id = tu_u16_low(request->wValue); - case HID_REQ_CONTROL_SET_REPORT: - if (stage == CONTROL_STAGE_SETUP) { - TU_VERIFY(request->wLength <= sizeof(p_hid->ctrl_buf)); - tud_control_xfer(rhport, request, p_hid->ctrl_buf, request->wLength); - } else if (stage == CONTROL_STAGE_ACK) { - uint8_t const report_type = tu_u16_high(request->wValue); - uint8_t const report_id = tu_u16_low(request->wValue); + uint8_t const* report_buf = p_hid->ctrl_buf; + uint16_t report_len = tu_min16(request->wLength, CFG_TUD_HID_EP_BUFSIZE); - uint8_t const *report_buf = p_hid->ctrl_buf; - uint16_t report_len = tu_min16(request->wLength, CFG_TUD_HID_EP_BUFSIZE); + // If host request a specific Report ID, extract report ID in buffer before invoking callback + if ((report_id != HID_REPORT_TYPE_INVALID) && (report_len > 1) && (report_id == report_buf[0])) { + report_buf++; + report_len--; + } - // If host request a specific Report ID, extract report ID in buffer before invoking callback - if ((report_id != HID_REPORT_TYPE_INVALID) && (report_len > 1) && (report_id == report_buf[0])) { - report_buf++; - report_len--; + tud_hid_set_report_cb(hid_itf, report_id, (hid_report_type_t) report_type, report_buf, report_len); } + break; - tud_hid_set_report_cb(hid_itf, report_id, (hid_report_type_t)report_type, report_buf, report_len); - } - break; - - case HID_REQ_CONTROL_SET_IDLE: - if (stage == CONTROL_STAGE_SETUP) { - p_hid->idle_rate = tu_u16_high(request->wValue); - if (tud_hid_set_idle_cb) { - // stall request if callback return false - TU_VERIFY(tud_hid_set_idle_cb(hid_itf, p_hid->idle_rate)); + case HID_REQ_CONTROL_SET_IDLE: + if (stage == CONTROL_STAGE_SETUP) { + p_hid->idle_rate = tu_u16_high(request->wValue); + TU_VERIFY(tud_hid_set_idle_cb(hid_itf, p_hid->idle_rate)); // stall if false + tud_control_status(rhport, request); } + break; - tud_control_status(rhport, request); - } - break; - - case HID_REQ_CONTROL_GET_IDLE: - if (stage == CONTROL_STAGE_SETUP) { - // TODO idle rate of report - tud_control_xfer(rhport, request, &p_hid->idle_rate, 1); - } - break; + case HID_REQ_CONTROL_GET_IDLE: + if (stage == CONTROL_STAGE_SETUP) { + // TODO idle rate of report + tud_control_xfer(rhport, request, &p_hid->idle_rate, 1); + } + break; - case HID_REQ_CONTROL_GET_PROTOCOL: - if (stage == CONTROL_STAGE_SETUP) { - tud_control_xfer(rhport, request, &p_hid->protocol_mode, 1); - } - break; + case HID_REQ_CONTROL_GET_PROTOCOL: + if (stage == CONTROL_STAGE_SETUP) { + tud_control_xfer(rhport, request, &p_hid->protocol_mode, 1); + } + break; - case HID_REQ_CONTROL_SET_PROTOCOL: - if (stage == CONTROL_STAGE_SETUP) { - tud_control_status(rhport, request); - } else if (stage == CONTROL_STAGE_ACK) { - p_hid->protocol_mode = (uint8_t)request->wValue; - if (tud_hid_set_protocol_cb) { + case HID_REQ_CONTROL_SET_PROTOCOL: + if (stage == CONTROL_STAGE_SETUP) { + tud_control_status(rhport, request); + } else if (stage == CONTROL_STAGE_ACK) { + p_hid->protocol_mode = (uint8_t) request->wValue; tud_hid_set_protocol_cb(hid_itf, p_hid->protocol_mode); } - } - break; + break; - default: - return false; // stall unsupported request + default: + return false; // stall unsupported request } } else { return false; // stall unsupported request @@ -354,45 +370,35 @@ bool hidd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t return true; } -bool hidd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) -{ - (void)result; - +bool hidd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) { uint8_t instance = 0; hidd_interface_t *p_hid = _hidd_itf; // Identify which interface to use for (instance = 0; instance < CFG_TUD_HID; instance++) { p_hid = &_hidd_itf[instance]; - if ((ep_addr == p_hid->ep_out) || (ep_addr == p_hid->ep_in)) + if ((ep_addr == p_hid->ep_out) || (ep_addr == p_hid->ep_in)) { break; + } } TU_ASSERT(instance < CFG_TUD_HID); - // Check if there was a problem - if (XFER_RESULT_SUCCESS != result) { // Inform application about the issue - if (tud_hid_report_fail_cb) { - tud_hid_report_fail_cb(instance, ep_addr, (uint16_t)xferred_bytes); + if (ep_addr == p_hid->ep_in) { + // Input report + if (XFER_RESULT_SUCCESS == result) { + tud_hid_report_complete_cb(instance, p_hid->epin_buf, (uint16_t) xferred_bytes); + } else { + tud_hid_report_failed_cb(instance, HID_REPORT_TYPE_INPUT, p_hid->epin_buf, (uint16_t) xferred_bytes); } - - // Allow a new transfer to be received if issue happened on an OUT endpoint - if (ep_addr == p_hid->ep_out) { - // Prepare the OUT endpoint to be able to receive a new transfer - TU_ASSERT(usbd_edpt_xfer(rhport, p_hid->ep_out, p_hid->epout_buf, sizeof(p_hid->epout_buf))); + } else { + // Output report + if (XFER_RESULT_SUCCESS == result) { + tud_hid_set_report_cb(instance, 0, HID_REPORT_TYPE_OUTPUT, p_hid->epout_buf, (uint16_t)xferred_bytes); + } else { + tud_hid_report_failed_cb(instance, HID_REPORT_TYPE_OUTPUT, p_hid->epout_buf, (uint16_t) xferred_bytes); } - return true; - } - - // Sent report successfully - if (ep_addr == p_hid->ep_in) { - if (tud_hid_report_complete_cb) { - tud_hid_report_complete_cb(instance, p_hid->epin_buf, (uint16_t)xferred_bytes); - } - } - // Received report successfully - else if (ep_addr == p_hid->ep_out) { - tud_hid_set_report_cb(instance, 0, HID_REPORT_TYPE_OUTPUT, p_hid->epout_buf, (uint16_t)xferred_bytes); + // prepare for new transfer TU_ASSERT(usbd_edpt_xfer(rhport, p_hid->ep_out, p_hid->epout_buf, sizeof(p_hid->epout_buf))); } diff --git a/src/class/hid/hid_device.h b/src/class/hid/hid_device.h index fcbf161c4..ab2e27373 100644 --- a/src/class/hid/hid_device.h +++ b/src/class/hid/hid_device.h @@ -24,8 +24,8 @@ * This file is part of the TinyUSB stack. */ -#ifndef _TUSB_HID_DEVICE_H_ -#define _TUSB_HID_DEVICE_H_ +#ifndef TUSB_HID_DEVICE_H_ +#define TUSB_HID_DEVICE_H_ #include "hid.h" @@ -48,8 +48,7 @@ #endif //--------------------------------------------------------------------+ -// Application API (Multiple Instances) -// CFG_TUD_HID > 1 +// Application API (Multiple Instances) i.e. CFG_TUD_HID > 1 //--------------------------------------------------------------------+ // Check if the interface is ready to use @@ -66,7 +65,7 @@ bool tud_hid_n_report(uint8_t instance, uint8_t report_id, void const* report, u // KEYBOARD: convenient helper to send keyboard report if application // use template layout report as defined by hid_keyboard_report_t -bool tud_hid_n_keyboard_report(uint8_t instance, uint8_t report_id, uint8_t modifier, uint8_t keycode[6]); +bool tud_hid_n_keyboard_report(uint8_t instance, uint8_t report_id, uint8_t modifier, const uint8_t keycode[6]); // MOUSE: convenient helper to send mouse report if application // use template layout report as defined by hid_mouse_report_t @@ -76,12 +75,6 @@ bool tud_hid_n_mouse_report(uint8_t instance, uint8_t report_id, uint8_t buttons // use template layout report as defined by hid_abs_mouse_report_t bool tud_hid_n_abs_mouse_report(uint8_t instance, uint8_t report_id, uint8_t buttons, int16_t x, int16_t y, int8_t vertical, int8_t horizontal); - -static inline bool tud_hid_abs_mouse_report(uint8_t report_id, uint8_t buttons, int16_t x, int16_t y, int8_t vertical, int8_t horizontal) -{ - return tud_hid_n_abs_mouse_report(0, report_id, buttons, x, y, vertical, horizontal); -} - // Gamepad: convenient helper to send gamepad report if application // use template layout report TUD_HID_REPORT_DESC_GAMEPAD bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id, int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons); @@ -89,16 +82,40 @@ bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id, int8_t x, int //--------------------------------------------------------------------+ // Application API (Single Port) //--------------------------------------------------------------------+ -static inline bool tud_hid_ready(void); -static inline uint8_t tud_hid_interface_protocol(void); -static inline uint8_t tud_hid_get_protocol(void); -static inline bool tud_hid_report(uint8_t report_id, void const* report, uint16_t len); -static inline bool tud_hid_keyboard_report(uint8_t report_id, uint8_t modifier, uint8_t keycode[6]); -static inline bool tud_hid_mouse_report(uint8_t report_id, uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal); -static inline bool tud_hid_gamepad_report(uint8_t report_id, int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons); +TU_ATTR_ALWAYS_INLINE static inline bool tud_hid_ready(void) { + return tud_hid_n_ready(0); +} + +TU_ATTR_ALWAYS_INLINE static inline uint8_t tud_hid_interface_protocol(void) { + return tud_hid_n_interface_protocol(0); +} + +TU_ATTR_ALWAYS_INLINE static inline uint8_t tud_hid_get_protocol(void) { + return tud_hid_n_get_protocol(0); +} + +TU_ATTR_ALWAYS_INLINE static inline bool tud_hid_report(uint8_t report_id, void const* report, uint16_t len) { + return tud_hid_n_report(0, report_id, report, len); +} + +TU_ATTR_ALWAYS_INLINE static inline bool tud_hid_keyboard_report(uint8_t report_id, uint8_t modifier, const uint8_t keycode[6]) { + return tud_hid_n_keyboard_report(0, report_id, modifier, keycode); +} + +TU_ATTR_ALWAYS_INLINE static inline bool tud_hid_mouse_report(uint8_t report_id, uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal) { + return tud_hid_n_mouse_report(0, report_id, buttons, x, y, vertical, horizontal); +} + +TU_ATTR_ALWAYS_INLINE static inline bool tud_hid_abs_mouse_report(uint8_t report_id, uint8_t buttons, int16_t x, int16_t y, int8_t vertical, int8_t horizontal) { + return tud_hid_n_abs_mouse_report(0, report_id, buttons, x, y, vertical, horizontal); +} + +TU_ATTR_ALWAYS_INLINE static inline bool tud_hid_gamepad_report(uint8_t report_id, int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons) { + return tud_hid_n_gamepad_report(0, report_id, x, y, z, rz, rx, ry, hat, buttons); +} //--------------------------------------------------------------------+ -// Callbacks (Weak is optional) +// Application Callbacks //--------------------------------------------------------------------+ // Invoked when received GET HID REPORT DESCRIPTOR request @@ -111,63 +128,25 @@ uint8_t const * tud_hid_descriptor_report_cb(uint8_t instance); uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen); // Invoked when received SET_REPORT control request or -// received data on OUT endpoint ( Report ID = 0, Type = 0 ) +// received data on OUT endpoint (Report ID = 0, Type = OUTPUT) void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize); // Invoked when received SET_PROTOCOL request // protocol is either HID_PROTOCOL_BOOT (0) or HID_PROTOCOL_REPORT (1) -TU_ATTR_WEAK void tud_hid_set_protocol_cb(uint8_t instance, uint8_t protocol); +void tud_hid_set_protocol_cb(uint8_t instance, uint8_t protocol); // Invoked when received SET_IDLE request. return false will stall the request -// - Idle Rate = 0 : only send report if there is changes, i.e skip duplication +// - Idle Rate = 0 : only send report if there is changes, i.e. skip duplication // - Idle Rate > 0 : skip duplication, but send at least 1 report every idle rate (in unit of 4 ms). -TU_ATTR_WEAK bool tud_hid_set_idle_cb(uint8_t instance, uint8_t idle_rate); +bool tud_hid_set_idle_cb(uint8_t instance, uint8_t idle_rate); // Invoked when sent REPORT successfully to host // Application can use this to send the next report // Note: For composite reports, report[0] is report ID -TU_ATTR_WEAK void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, uint16_t len); +void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, uint16_t len); // Invoked when a transfer wasn't successful -TU_ATTR_WEAK void tud_hid_report_fail_cb(uint8_t instance, uint8_t ep_addr, uint16_t len); - -//--------------------------------------------------------------------+ -// Inline Functions -//--------------------------------------------------------------------+ -static inline bool tud_hid_ready(void) -{ - return tud_hid_n_ready(0); -} - -static inline uint8_t tud_hid_interface_protocol(void) -{ - return tud_hid_n_interface_protocol(0); -} - -static inline uint8_t tud_hid_get_protocol(void) -{ - return tud_hid_n_get_protocol(0); -} - -static inline bool tud_hid_report(uint8_t report_id, void const* report, uint16_t len) -{ - return tud_hid_n_report(0, report_id, report, len); -} - -static inline bool tud_hid_keyboard_report(uint8_t report_id, uint8_t modifier, uint8_t keycode[6]) -{ - return tud_hid_n_keyboard_report(0, report_id, modifier, keycode); -} - -static inline bool tud_hid_mouse_report(uint8_t report_id, uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal) -{ - return tud_hid_n_mouse_report(0, report_id, buttons, x, y, vertical, horizontal); -} - -static inline bool tud_hid_gamepad_report(uint8_t report_id, int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons) -{ - return tud_hid_n_gamepad_report(0, report_id, x, y, z, rz, rx, ry, hat, buttons); -} +void tud_hid_report_failed_cb(uint8_t instance, hid_report_type_t report_type, uint8_t const* report, uint16_t xferred_bytes); /* --------------------------------------------------------------------+ * HID Report Descriptor Template @@ -645,9 +624,8 @@ uint16_t hidd_open (uint8_t rhport, tusb_desc_interface_t const * itf bool hidd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); bool hidd_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); - #ifdef __cplusplus } #endif -#endif /* _TUSB_HID_DEVICE_H_ */ +#endif diff --git a/src/class/hid/hid_host.c b/src/class/hid/hid_host.c index 115a8a4df..7639a8fc6 100644 --- a/src/class/hid/hid_host.c +++ b/src/class/hid/hid_host.c @@ -657,7 +657,9 @@ uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* report_info_arr, uint8_t const data8 = desc_report[0]; TU_LOG(3, "tag = %d, type = %d, size = %d, data = ", tag, type, size); - for (uint32_t i = 0; i < size; i++) TU_LOG(3, "%02X ", desc_report[i]); + for (uint32_t i = 0; i < size; i++) { + TU_LOG(3, "%02X ", desc_report[i]); + } TU_LOG(3, "\r\n"); switch (type) { diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index 8a0fd4417..5f2dcabad 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -315,9 +315,8 @@ static void _ff_pull_n(tu_fifo_t* f, void* app_buf, uint16_t n, uint16_t rd_ptr, // Read data wrapped part if (wrap_bytes > 0) _ff_pull_const_addr(app_buf, ff_buf, wrap_bytes); } -#endif break; - +#endif default: break; } } diff --git a/src/common/tusb_fifo.h b/src/common/tusb_fifo.h index 6c0efb509..879acda4f 100644 --- a/src/common/tusb_fifo.h +++ b/src/common/tusb_fifo.h @@ -154,14 +154,14 @@ void tu_fifo_config_mutex(tu_fifo_t *f, osal_mutex_t wr_mutex, osal_mutex_t rd_m #define tu_fifo_config_mutex(_f, _wr_mutex, _rd_mutex) #endif -bool tu_fifo_write (tu_fifo_t* f, void const * p_data); -uint16_t tu_fifo_write_n (tu_fifo_t* f, void const * p_data, uint16_t n); +bool tu_fifo_write (tu_fifo_t* f, void const * data); +uint16_t tu_fifo_write_n (tu_fifo_t* f, void const * data, uint16_t n); #ifdef TUP_MEM_CONST_ADDR uint16_t tu_fifo_write_n_const_addr_full_words (tu_fifo_t* f, const void * data, uint16_t n); #endif -bool tu_fifo_read (tu_fifo_t* f, void * p_buffer); -uint16_t tu_fifo_read_n (tu_fifo_t* f, void * p_buffer, uint16_t n); +bool tu_fifo_read (tu_fifo_t* f, void * buffer); +uint16_t tu_fifo_read_n (tu_fifo_t* f, void * buffer, uint16_t n); #ifdef TUP_MEM_CONST_ADDR uint16_t tu_fifo_read_n_const_addr_full_words (tu_fifo_t* f, void * buffer, uint16_t n); #endif diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h index 80826c895..0a4462a0a 100644 --- a/src/common/tusb_mcu.h +++ b/src/common/tusb_mcu.h @@ -138,21 +138,21 @@ #elif TU_CHECK_MCU(OPT_MCU_SAMG) #define TUP_DCD_ENDPOINT_MAX 6 - #define TUP_DCD_ENDPOINT_EXCLUSIVE_NUMBER + #define TUD_ENDPOINT_ONE_DIRECTION_ONLY #elif TU_CHECK_MCU(OPT_MCU_SAMX7X) #define TUP_DCD_ENDPOINT_MAX 10 #define TUP_RHPORT_HIGHSPEED 1 - #define TUP_DCD_ENDPOINT_EXCLUSIVE_NUMBER + #define TUD_ENDPOINT_ONE_DIRECTION_ONLY #elif TU_CHECK_MCU(OPT_MCU_PIC32MZ) #define TUP_DCD_ENDPOINT_MAX 8 - #define TUP_DCD_ENDPOINT_EXCLUSIVE_NUMBER + #define TUD_ENDPOINT_ONE_DIRECTION_ONLY #elif TU_CHECK_MCU(OPT_MCU_PIC32MX, OPT_MCU_PIC32MM, OPT_MCU_PIC32MK) || \ TU_CHECK_MCU(OPT_MCU_PIC24, OPT_MCU_DSPIC33) #define TUP_DCD_ENDPOINT_MAX 16 - #define TUP_DCD_ENDPOINT_EXCLUSIVE_NUMBER + #define TUD_ENDPOINT_ONE_DIRECTION_ONLY //--------------------------------------------------------------------+ // ST @@ -195,7 +195,6 @@ #elif TU_CHECK_MCU(OPT_MCU_STM32F4) #define TUP_USBIP_DWC2 #define TUP_USBIP_DWC2_STM32 - #define TUP_USBIP_DWC2_TEST_MODE // For most mcu, FS has 4, HS has 6. TODO 446/469/479 HS has 9 #define TUP_DCD_ENDPOINT_MAX 6 @@ -210,7 +209,6 @@ // MCU with on-chip HS Phy #if defined(STM32F723xx) || defined(STM32F730xx) || defined(STM32F733xx) #define TUP_RHPORT_HIGHSPEED 1 // Port0: FS, Port1: HS - #define TUP_USBIP_DWC2_TEST_MODE #endif #elif TU_CHECK_MCU(OPT_MCU_STM32H7) @@ -285,7 +283,6 @@ defined(STM32U5F7xx) || defined(STM32U5F9xx) || defined(STM32U5G7xx) || defined(STM32U5G9xx) #define TUP_DCD_ENDPOINT_MAX 9 #define TUP_RHPORT_HIGHSPEED 1 - #define TUP_USBIP_DWC2_TEST_MODE #else #define TUP_DCD_ENDPOINT_MAX 6 #endif @@ -302,7 +299,7 @@ #elif TU_CHECK_MCU(OPT_MCU_CXD56) #define TUP_DCD_ENDPOINT_MAX 7 #define TUP_RHPORT_HIGHSPEED 1 - #define TUP_DCD_ENDPOINT_EXCLUSIVE_NUMBER + #define TUD_ENDPOINT_ONE_DIRECTION_ONLY //--------------------------------------------------------------------+ // TI @@ -311,6 +308,8 @@ #define TUP_DCD_ENDPOINT_MAX 8 #elif TU_CHECK_MCU(OPT_MCU_MSP432E4, OPT_MCU_TM4C123, OPT_MCU_TM4C129) + #define TUP_USBIP_MUSB + #define TUP_USBIP_MUSB_TI #define TUP_DCD_ENDPOINT_MAX 8 //--------------------------------------------------------------------+ @@ -337,10 +336,14 @@ //--------------------------------------------------------------------+ #elif TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3) #define TUP_USBIP_DWC2 + #define TUP_USBIP_DWC2_ESP32 #define TUP_DCD_ENDPOINT_MAX 6 -#elif TU_CHECK_MCU(OPT_MCU_ESP32, OPT_MCU_ESP32C2, OPT_MCU_ESP32C3, OPT_MCU_ESP32C6, OPT_MCU_ESP32H2) && (CFG_TUD_ENABLED || !(defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421)) +#elif TU_CHECK_MCU(OPT_MCU_ESP32, OPT_MCU_ESP32C2, OPT_MCU_ESP32C3, OPT_MCU_ESP32C6, OPT_MCU_ESP32H2) + #if (CFG_TUD_ENABLED || !(defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421)) #error "MCUs are only supported with CFG_TUH_MAX3421 enabled" + #endif + #define TUP_DCD_ENDPOINT_MAX 0 //--------------------------------------------------------------------+ // Dialog @@ -398,10 +401,12 @@ #elif TU_CHECK_MCU(OPT_MCU_FT90X) #define TUP_DCD_ENDPOINT_MAX 8 #define TUP_RHPORT_HIGHSPEED 1 + #define TUD_ENDPOINT_ONE_DIRECTION_ONLY #elif TU_CHECK_MCU(OPT_MCU_FT93X) #define TUP_DCD_ENDPOINT_MAX 16 #define TUP_RHPORT_HIGHSPEED 1 + #define TUD_ENDPOINT_ONE_DIRECTION_ONLY //--------------------------------------------------------------------+ // Allwinner @@ -468,6 +473,16 @@ #define TUP_RHPORT_HIGHSPEED CFG_TUD_WCH_USBIP_USBHS #define TUP_DCD_ENDPOINT_MAX (CFG_TUD_WCH_USBIP_USBHS ? 16 : 8) +//--------------------------------------------------------------------+ +// Analog Devices +//--------------------------------------------------------------------+ +#elif TU_CHECK_MCU(OPT_MCU_MAX32650, OPT_MCU_MAX32666, OPT_MCU_MAX32690, OPT_MCU_MAX78002) + #define TUP_USBIP_MUSB + #define TUP_USBIP_MUSB_ADI + #define TUP_DCD_ENDPOINT_MAX 12 + #define TUP_RHPORT_HIGHSPEED 1 + #define TUD_ENDPOINT_ONE_DIRECTION_ONLY + #endif //--------------------------------------------------------------------+ @@ -504,7 +519,8 @@ #define TU_ATTR_FAST_FUNC #endif -#if defined(TUP_USBIP_DWC2) || defined(TUP_USBIP_FSDEV) +// USBIP that support ISO alloc & activate API +#if defined(TUP_USBIP_DWC2) || defined(TUP_USBIP_FSDEV) || defined(TUP_USBIP_MUSB) #define TUP_DCD_EDPT_ISO_ALLOC #endif diff --git a/src/common/tusb_types.h b/src/common/tusb_types.h index b571f9b72..1501a5af6 100644 --- a/src/common/tusb_types.h +++ b/src/common/tusb_types.h @@ -214,6 +214,15 @@ enum { #define TUSB_DESC_CONFIG_POWER_MA(x) ((x)/2) +// USB 2.0 Spec Table 9-7: Test Mode Selectors +typedef enum { + TUSB_FEATURE_TEST_J = 1, + TUSB_FEATURE_TEST_K, + TUSB_FEATURE_TEST_SE0_NAK, + TUSB_FEATURE_TEST_PACKET, + TUSB_FEATURE_TEST_FORCE_ENABLE, +} tusb_feature_test_mode_t; + //--------------------------------------------------------------------+ // //--------------------------------------------------------------------+ diff --git a/src/common/tusb_verify.h b/src/common/tusb_verify.h index dde0550d3..4344575b7 100644 --- a/src/common/tusb_verify.h +++ b/src/common/tusb_verify.h @@ -56,8 +56,8 @@ * #define TU_VERIFY(cond) if(cond) return false; * #define TU_VERIFY(cond,ret) if(cond) return ret; * - * #define TU_ASSERT(cond) if(cond) {_MESS_FAILED(); TU_BREAKPOINT(), return false;} - * #define TU_ASSERT(cond,ret) if(cond) {_MESS_FAILED(); TU_BREAKPOINT(), return ret;} + * #define TU_ASSERT(cond) if(cond) {TU_MESS_FAILED(); TU_BREAKPOINT(), return false;} + * #define TU_ASSERT(cond,ret) if(cond) {TU_MESS_FAILED(); TU_BREAKPOINT(), return ret;} *------------------------------------------------------------------*/ #ifdef __cplusplus @@ -70,9 +70,9 @@ #if CFG_TUSB_DEBUG #include <stdio.h> - #define _MESS_FAILED() tu_printf("%s %d: ASSERT FAILED\r\n", __func__, __LINE__) + #define TU_MESS_FAILED() tu_printf("%s %d: ASSERT FAILED\r\n", __func__, __LINE__) #else - #define _MESS_FAILED() do {} while (0) + #define TU_MESS_FAILED() do {} while (0) #endif // Halt CPU (breakpoint) when hitting error, only apply for Cortex M3, M4, M7, M33. M55 @@ -119,7 +119,7 @@ *------------------------------------------------------------------*/ #define TU_ASSERT_DEFINE(_cond, _ret) \ do { \ - if ( !(_cond) ) { _MESS_FAILED(); TU_BREAKPOINT(); return _ret; } \ + if ( !(_cond) ) { TU_MESS_FAILED(); TU_BREAKPOINT(); return _ret; } \ } while(0) #define TU_ASSERT_1ARGS(_cond) TU_ASSERT_DEFINE(_cond, false) diff --git a/src/device/dcd.h b/src/device/dcd.h index f6735b077..3ef5188fc 100644 --- a/src/device/dcd.h +++ b/src/device/dcd.h @@ -40,19 +40,15 @@ //--------------------------------------------------------------------+ typedef enum { - DCD_EVENT_INVALID = 0, - DCD_EVENT_BUS_RESET, - DCD_EVENT_UNPLUGGED, - DCD_EVENT_SOF, - DCD_EVENT_SUSPEND, // TODO LPM Sleep L1 support - DCD_EVENT_RESUME, - - DCD_EVENT_SETUP_RECEIVED, - DCD_EVENT_XFER_COMPLETE, - - // Not an DCD event, just a convenient way to defer ISR function - USBD_EVENT_FUNC_CALL, - + DCD_EVENT_INVALID = 0, // 0 + DCD_EVENT_BUS_RESET, // 1 + DCD_EVENT_UNPLUGGED, // 2 + DCD_EVENT_SOF, // 3 + DCD_EVENT_SUSPEND, // 4 TODO LPM Sleep L1 support + DCD_EVENT_RESUME, // 5 + DCD_EVENT_SETUP_RECEIVED, // 6 + DCD_EVENT_XFER_COMPLETE, // 7 + USBD_EVENT_FUNC_CALL, // 8 Not an DCD event, just a convenient way to defer ISR function DCD_EVENT_COUNT } dcd_eventid_t; @@ -89,14 +85,6 @@ typedef struct TU_ATTR_ALIGNED(4) { }; } dcd_event_t; -typedef enum { - TEST_J = 1, - TEST_K, - TEST_SE0_NAK, - TEST_PACKET, - TEST_FORCE_ENABLE, -} test_mode_t; - //TU_VERIFY_STATIC(sizeof(dcd_event_t) <= 12, "size is not correct"); //--------------------------------------------------------------------+ @@ -150,11 +138,8 @@ void dcd_disconnect(uint8_t rhport); void dcd_sof_enable(uint8_t rhport, bool en); #if CFG_TUD_TEST_MODE -// Check if the test mode is supported, returns true is test mode selector is supported -bool dcd_check_test_mode_support(test_mode_t test_selector) TU_ATTR_WEAK; - // Put device into a test mode (needs power cycle to quit) -void dcd_enter_test_mode(uint8_t rhport, test_mode_t test_selector) TU_ATTR_WEAK; +void dcd_enter_test_mode(uint8_t rhport, tusb_feature_test_mode_t test_selector); #endif //--------------------------------------------------------------------+ // Endpoint API @@ -172,10 +157,6 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc // required for multiple configuration support. void dcd_edpt_close_all (uint8_t rhport); -// Close an endpoint. -// Since it is weak, caller must TU_ASSERT this function's existence before calling it. -void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr) TU_ATTR_WEAK; - // Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes); @@ -190,12 +171,19 @@ void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr); // This API never calls with control endpoints, since it is auto cleared when receiving setup packet void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr); +#ifdef TUP_DCD_EDPT_ISO_ALLOC // Allocate packet buffer used by ISO endpoints // Some MCU need manual packet buffer allocation, we allocate the largest size to avoid clustering -TU_ATTR_WEAK bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size); +bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size); // Configure and enable an ISO endpoint according to descriptor -TU_ATTR_WEAK bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc); +bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * desc_ep); + +#else +// Close an endpoint. +void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr); + +#endif //--------------------------------------------------------------------+ // Event API (implemented by stack) diff --git a/src/device/usbd.c b/src/device/usbd.c index 800d9c824..67faf0da7 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -46,13 +46,46 @@ // Weak stubs: invoked if no strong implementation is available //--------------------------------------------------------------------+ TU_ATTR_WEAK void tud_event_hook_cb(uint8_t rhport, uint32_t eventid, bool in_isr) { - (void)rhport; - (void)eventid; - (void)in_isr; + (void) rhport; + (void) eventid; + (void) in_isr; } TU_ATTR_WEAK void tud_sof_cb(uint32_t frame_count) { - (void)frame_count; + (void) frame_count; +} + +TU_ATTR_WEAK uint8_t const* tud_descriptor_bos_cb(void) { + return NULL; +} + +TU_ATTR_WEAK uint8_t const* tud_descriptor_device_qualifier_cb(void) { + return NULL; +} + +TU_ATTR_WEAK uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index) { + (void) index; + return NULL; +} + +TU_ATTR_WEAK void tud_mount_cb(void) { +} + +TU_ATTR_WEAK void tud_umount_cb(void) { +} + +TU_ATTR_WEAK void tud_suspend_cb(bool remote_wakeup_en) { + (void) remote_wakeup_en; +} + +TU_ATTR_WEAK void tud_resume_cb(void) { +} + +TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const* request) { + (void) rhport; + (void) stage; + (void) request; + return false; } TU_ATTR_WEAK bool dcd_deinit(uint8_t rhport) { @@ -87,7 +120,6 @@ typedef struct { }; volatile uint8_t cfg_num; // current active configuration (0x00 is not configured) uint8_t speed; - volatile uint8_t setup_count; volatile uint8_t sof_consumer; uint8_t itf2drv[CFG_TUD_INTERFACE_MAX]; // map interface number to driver (0xff is invalid) @@ -98,6 +130,7 @@ typedef struct { }usbd_device_t; tu_static usbd_device_t _usbd_dev; +static volatile uint8_t _usbd_queued_setup; //--------------------------------------------------------------------+ // Class Driver @@ -321,9 +354,17 @@ TU_ATTR_ALWAYS_INLINE static inline bool queue_event(dcd_event_t const * event, static bool process_control_request(uint8_t rhport, tusb_control_request_t const * p_request); static bool process_set_config(uint8_t rhport, uint8_t cfg_num); static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const * p_request); + #if CFG_TUD_TEST_MODE -static bool process_test_mode_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); +static bool process_test_mode_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) { + TU_VERIFY(CONTROL_STAGE_ACK == stage); + uint8_t const selector = tu_u16_high(request->wIndex); + TU_LOG_USBD(" Enter Test Mode (test selector index: %d)\r\n", selector); + dcd_enter_test_mode(rhport, (tusb_feature_test_mode_t) selector); + return true; +} #endif + // from usbd_control.c void usbd_control_reset(void); void usbd_control_set_request(tusb_control_request_t const *request); @@ -418,6 +459,7 @@ bool tud_init(uint8_t rhport) { TU_LOG_INT(CFG_TUD_LOG_LEVEL, sizeof(tu_edpt_stream_t)); tu_varclr(&_usbd_dev); + _usbd_queued_setup = 0; #if OSAL_MUTEX_REQUIRED // Init device mutex @@ -549,13 +591,14 @@ void tud_task_ext(uint32_t timeout_ms, bool in_isr) { case DCD_EVENT_UNPLUGGED: TU_LOG_USBD("\r\n"); usbd_reset(event.rhport); - if (tud_umount_cb) tud_umount_cb(); + tud_umount_cb(); break; case DCD_EVENT_SETUP_RECEIVED: - _usbd_dev.setup_count--; + TU_ASSERT(_usbd_queued_setup > 0,); + _usbd_queued_setup--; TU_LOG_BUF(CFG_TUD_LOG_LEVEL, &event.setup_received, 8); - if (_usbd_dev.setup_count) { + if (_usbd_queued_setup) { TU_LOG_USBD(" Skipped since there is other SETUP in queue\r\n"); break; } @@ -609,7 +652,7 @@ void tud_task_ext(uint32_t timeout_ms, bool in_isr) { // e.g suspend -> resume -> unplug/plug. Skip suspend/resume if not connected if (_usbd_dev.connected) { TU_LOG_USBD(": Remote Wakeup = %u\r\n", _usbd_dev.remote_wakeup_en); - if (tud_suspend_cb) tud_suspend_cb(_usbd_dev.remote_wakeup_en); + tud_suspend_cb(_usbd_dev.remote_wakeup_en); } else { TU_LOG_USBD(" Skipped\r\n"); } @@ -618,7 +661,7 @@ void tud_task_ext(uint32_t timeout_ms, bool in_isr) { case DCD_EVENT_RESUME: if (_usbd_dev.connected) { TU_LOG_USBD("\r\n"); - if (tud_resume_cb) tud_resume_cb(); + tud_resume_cb(); } else { TU_LOG_USBD(" Skipped\r\n"); } @@ -667,8 +710,6 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const // Vendor request if ( p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_VENDOR ) { - TU_VERIFY(tud_vendor_control_xfer_cb); - usbd_control_set_complete_callback(tud_vendor_control_xfer_cb); return tud_vendor_control_xfer_cb(rhport, CONTROL_STAGE_SETUP, p_request); } @@ -695,7 +736,7 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const } if ( TUSB_REQ_TYPE_STANDARD != p_request->bmRequestType_bit.type ) { - // Non standard request is not supported + // Non-standard request is not supported TU_BREAKPOINT(); return false; } @@ -739,17 +780,23 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const _usbd_dev.speed = speed; // restore speed } + _usbd_dev.cfg_num = cfg_num; + // Handle the new configuration and execute the corresponding callback if ( cfg_num ) { // switch to new configuration if not zero - TU_ASSERT( process_set_config(rhport, cfg_num) ); - if ( tud_mount_cb ) tud_mount_cb(); + if (!process_set_config(rhport, cfg_num)) { + TU_MESS_FAILED(); + TU_BREAKPOINT(); + _usbd_dev.cfg_num = 0; + return false; + } + tud_mount_cb(); } else { - if ( tud_umount_cb ) tud_umount_cb(); + tud_umount_cb(); } } - _usbd_dev.cfg_num = cfg_num; tud_control_status(rhport, p_request); } break; @@ -759,43 +806,27 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const break; case TUSB_REQ_SET_FEATURE: - // Handle the feature selector - switch(p_request->wValue) - { - // Support for remote wakeup + switch(p_request->wValue) { case TUSB_REQ_FEATURE_REMOTE_WAKEUP: TU_LOG_USBD(" Enable Remote Wakeup\r\n"); - // Host may enable remote wake up before suspending especially HID device _usbd_dev.remote_wakeup_en = true; tud_control_status(rhport, p_request); break; -#if CFG_TUD_TEST_MODE - // Support for TEST_MODE + #if CFG_TUD_TEST_MODE case TUSB_REQ_FEATURE_TEST_MODE: { // Only handle the test mode if supported and valid - TU_VERIFY(dcd_enter_test_mode && dcd_check_test_mode_support && 0 == tu_u16_low(p_request->wIndex)); - - uint8_t selector = tu_u16_high(p_request->wIndex); - - // Stall request if the selected test mode isn't supported - if (!dcd_check_test_mode_support((test_mode_t)selector)) - { - TU_LOG_USBD(" Unsupported Test Mode (test selector index: %d)\r\n", selector); - - return false; - } + TU_VERIFY(0 == tu_u16_low(p_request->wIndex)); - // Acknowledge request - tud_control_status(rhport, p_request); - - TU_LOG_USBD(" Enter Test Mode (test selector index: %d)\r\n", selector); + uint8_t const selector = tu_u16_high(p_request->wIndex); + TU_VERIFY(TUSB_FEATURE_TEST_J <= selector && selector <= TUSB_FEATURE_TEST_FORCE_ENABLE); usbd_control_set_complete_callback(process_test_mode_cb); + tud_control_status(rhport, p_request); break; } -#endif /* CFG_TUD_TEST_MODE */ + #endif /* CFG_TUD_TEST_MODE */ // Stall unsupported feature selector default: return false; @@ -1029,39 +1060,34 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const switch(desc_type) { - case TUSB_DESC_DEVICE: - { + case TUSB_DESC_DEVICE: { TU_LOG_USBD(" Device\r\n"); void* desc_device = (void*) (uintptr_t) tud_descriptor_device_cb(); + TU_ASSERT(desc_device); // Only response with exactly 1 Packet if: not addressed and host requested more data than device descriptor has. // This only happens with the very first get device descriptor and EP0 size = 8 or 16. if ((CFG_TUD_ENDPOINT0_SIZE < sizeof(tusb_desc_device_t)) && !_usbd_dev.addressed && - ((tusb_control_request_t const*) p_request)->wLength > sizeof(tusb_desc_device_t)) - { + ((tusb_control_request_t const*) p_request)->wLength > sizeof(tusb_desc_device_t)) { // Hack here: we modify the request length to prevent usbd_control response with zlp // since we are responding with 1 packet & less data than wLength. tusb_control_request_t mod_request = *p_request; mod_request.wLength = CFG_TUD_ENDPOINT0_SIZE; return tud_control_xfer(rhport, &mod_request, desc_device, CFG_TUD_ENDPOINT0_SIZE); - }else - { + }else { return tud_control_xfer(rhport, p_request, desc_device, sizeof(tusb_desc_device_t)); } } // break; // unreachable - case TUSB_DESC_BOS: - { + case TUSB_DESC_BOS: { TU_LOG_USBD(" BOS\r\n"); // requested by host if USB > 2.0 ( i.e 2.1 or 3.x ) - if (!tud_descriptor_bos_cb) return false; - uintptr_t desc_bos = (uintptr_t) tud_descriptor_bos_cb(); - TU_ASSERT(desc_bos); + TU_VERIFY(desc_bos); // Use offsetof to avoid pointer to the odd/misaligned address uint16_t const total_len = tu_le16toh( tu_unaligned_read16((const void*) (desc_bos + offsetof(tusb_desc_bos_t, wTotalLength))) ); @@ -1071,24 +1097,20 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const // break; // unreachable case TUSB_DESC_CONFIGURATION: - case TUSB_DESC_OTHER_SPEED_CONFIG: - { + case TUSB_DESC_OTHER_SPEED_CONFIG: { uintptr_t desc_config; - if ( desc_type == TUSB_DESC_CONFIGURATION ) - { + if ( desc_type == TUSB_DESC_CONFIGURATION ) { TU_LOG_USBD(" Configuration[%u]\r\n", desc_index); desc_config = (uintptr_t) tud_descriptor_configuration_cb(desc_index); - }else - { + TU_ASSERT(desc_config); + }else { // Host only request this after getting Device Qualifier descriptor TU_LOG_USBD(" Other Speed Configuration\r\n"); - TU_VERIFY( tud_descriptor_other_speed_configuration_cb ); desc_config = (uintptr_t) tud_descriptor_other_speed_configuration_cb(desc_index); + TU_VERIFY(desc_config); } - TU_ASSERT(desc_config); - // Use offsetof to avoid pointer to the odd/misaligned address uint16_t const total_len = tu_le16toh( tu_unaligned_read16((const void*) (desc_config + offsetof(tusb_desc_configuration_t, wTotalLength))) ); @@ -1109,16 +1131,10 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const } // break; // unreachable - case TUSB_DESC_DEVICE_QUALIFIER: - { + case TUSB_DESC_DEVICE_QUALIFIER: { TU_LOG_USBD(" Device Qualifier\r\n"); - - TU_VERIFY( tud_descriptor_device_qualifier_cb ); - uint8_t const* desc_qualifier = tud_descriptor_device_qualifier_cb(); TU_VERIFY(desc_qualifier); - - // first byte of descriptor is its size return tud_control_xfer(rhport, p_request, (void*) (uintptr_t) desc_qualifier, tu_desc_len(desc_qualifier)); } // break; // unreachable @@ -1127,20 +1143,6 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const } } -#if CFG_TUD_TEST_MODE -static bool process_test_mode_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) -{ - // At this point it should already be ensured that dcd_enter_test_mode() is defined - - // Only enter the test mode after the request for it has completed - TU_VERIFY(CONTROL_STAGE_ACK == stage); - - dcd_enter_test_mode(rhport, (test_mode_t)tu_u16_high(request->wIndex)); - - return true; -} -#endif /* CFG_TUD_TEST_MODE */ - //--------------------------------------------------------------------+ // DCD Event Handler //--------------------------------------------------------------------+ @@ -1199,7 +1201,7 @@ TU_ATTR_FAST_FUNC void dcd_event_handler(dcd_event_t const* event, bool in_isr) break; case DCD_EVENT_SETUP_RECEIVED: - _usbd_dev.setup_count++; + _usbd_queued_setup++; send = true; break; @@ -1416,9 +1418,12 @@ bool usbd_edpt_stalled(uint8_t rhport, uint8_t ep_addr) { * In progress transfers on this EP may be delivered after this call. */ void usbd_edpt_close(uint8_t rhport, uint8_t ep_addr) { +#ifdef TUP_DCD_EDPT_ISO_ALLOC + (void) rhport; (void) ep_addr; + // ISO alloc/activate Should be used instead +#else rhport = _usbd_rhport; - TU_ASSERT(dcd_edpt_close, /**/); TU_LOG_USBD(" CLOSING Endpoint: 0x%02X\r\n", ep_addr); uint8_t const epnum = tu_edpt_number(ep_addr); @@ -1428,6 +1433,7 @@ void usbd_edpt_close(uint8_t rhport, uint8_t ep_addr) { _usbd_dev.ep_status[epnum][dir].stalled = 0; _usbd_dev.ep_status[epnum][dir].busy = 0; _usbd_dev.ep_status[epnum][dir].claimed = 0; +#endif return; } @@ -1450,21 +1456,24 @@ void usbd_sof_enable(uint8_t rhport, sof_consumer_t consumer, bool en) { } bool usbd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { +#ifdef TUP_DCD_EDPT_ISO_ALLOC rhport = _usbd_rhport; - TU_ASSERT(dcd_edpt_iso_alloc); TU_ASSERT(tu_edpt_number(ep_addr) < CFG_TUD_ENDPPOINT_MAX); - return dcd_edpt_iso_alloc(rhport, ep_addr, largest_packet_size); +#else + (void) rhport; (void) ep_addr; (void) largest_packet_size; + return false; +#endif } bool usbd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const* desc_ep) { +#ifdef TUP_DCD_EDPT_ISO_ALLOC rhport = _usbd_rhport; uint8_t const epnum = tu_edpt_number(desc_ep->bEndpointAddress); uint8_t const dir = tu_edpt_dir(desc_ep->bEndpointAddress); - TU_ASSERT(dcd_edpt_iso_activate); TU_ASSERT(epnum < CFG_TUD_ENDPPOINT_MAX); TU_ASSERT(tu_edpt_validate(desc_ep, (tusb_speed_t) _usbd_dev.speed)); @@ -1472,6 +1481,10 @@ bool usbd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const* desc_ep) _usbd_dev.ep_status[epnum][dir].busy = 0; _usbd_dev.ep_status[epnum][dir].claimed = 0; return dcd_edpt_iso_activate(rhport, desc_ep); +#else + (void) rhport; (void) desc_ep; + return false; +#endif } #endif diff --git a/src/device/usbd.h b/src/device/usbd.h index e47f674ea..7913096e3 100644 --- a/src/device/usbd.h +++ b/src/device/usbd.h @@ -109,7 +109,7 @@ bool tud_control_xfer(uint8_t rhport, tusb_control_request_t const * request, vo bool tud_control_status(uint8_t rhport, tusb_control_request_t const * request); //--------------------------------------------------------------------+ -// Application Callbacks (WEAK is optional) +// Application Callbacks //--------------------------------------------------------------------+ // Invoked when received GET DEVICE DESCRIPTOR request @@ -126,31 +126,31 @@ uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid); // Invoked when received GET BOS DESCRIPTOR request // Application return pointer to descriptor -TU_ATTR_WEAK uint8_t const * tud_descriptor_bos_cb(void); +uint8_t const * tud_descriptor_bos_cb(void); // Invoked when received GET DEVICE QUALIFIER DESCRIPTOR request // Application return pointer to descriptor, whose contents must exist long enough for transfer to complete. // device_qualifier descriptor describes information about a high-speed capable device that would // change if the device were operating at the other speed. If not highspeed capable stall this request. -TU_ATTR_WEAK uint8_t const* tud_descriptor_device_qualifier_cb(void); +uint8_t const* tud_descriptor_device_qualifier_cb(void); // Invoked when received GET OTHER SEED CONFIGURATION DESCRIPTOR request // Application return pointer to descriptor, whose contents must exist long enough for transfer to complete // Configuration descriptor in the other speed e.g if high speed then this is for full speed and vice versa -TU_ATTR_WEAK uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index); +uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index); // Invoked when device is mounted (configured) -TU_ATTR_WEAK void tud_mount_cb(void); +void tud_mount_cb(void); // Invoked when device is unmounted -TU_ATTR_WEAK void tud_umount_cb(void); +void tud_umount_cb(void); // Invoked when usb bus is suspended // Within 7ms, device must draw an average of current less than 2.5 mA from bus -TU_ATTR_WEAK void tud_suspend_cb(bool remote_wakeup_en); +void tud_suspend_cb(bool remote_wakeup_en); // Invoked when usb bus is resumed -TU_ATTR_WEAK void tud_resume_cb(void); +void tud_resume_cb(void); // Invoked when there is a new usb event, which need to be processed by tud_task()/tud_task_ext() void tud_event_hook_cb(uint8_t rhport, uint32_t eventid, bool in_isr); @@ -159,7 +159,7 @@ void tud_event_hook_cb(uint8_t rhport, uint32_t eventid, bool in_isr); void tud_sof_cb(uint32_t frame_count); // Invoked when received control request with VENDOR TYPE -TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); +bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); //--------------------------------------------------------------------+ // Binary Device Object Store (BOS) Descriptor Templates @@ -434,8 +434,8 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb /* Standard AS Isochronous Feedback Endpoint Descriptor(4.10.2.1) */ #define TUD_AUDIO_DESC_STD_AS_ISO_FB_EP_LEN 7 -#define TUD_AUDIO_DESC_STD_AS_ISO_FB_EP(_ep, _interval) \ - TUD_AUDIO_DESC_STD_AS_ISO_FB_EP_LEN, TUSB_DESC_ENDPOINT, _ep, (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_NO_SYNC | (uint8_t)TUSB_ISO_EP_ATT_EXPLICIT_FB), U16_TO_U8S_LE(4), _interval +#define TUD_AUDIO_DESC_STD_AS_ISO_FB_EP(_ep, _epsize, _interval) \ + TUD_AUDIO_DESC_STD_AS_ISO_FB_EP_LEN, TUSB_DESC_ENDPOINT, _ep, (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_NO_SYNC | (uint8_t)TUSB_ISO_EP_ATT_EXPLICIT_FB), U16_TO_U8S_LE(_epsize), _interval // AUDIO simple descriptor (UAC2) for 1 microphone input // - 1 Input Terminal, 1 Feature Unit (Mute and Volume Control), 1 Output Terminal, 1 Clock Source @@ -553,7 +553,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN\ + TUD_AUDIO_DESC_STD_AS_ISO_FB_EP_LEN) -#define TUD_AUDIO_SPEAKER_MONO_FB_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epout, _epsize, _epfb) \ +#define TUD_AUDIO_SPEAKER_MONO_FB_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epout, _epoutsize, _epfb, _epfbsize) \ /* Standard Interface Association Descriptor (IAD) */\ TUD_AUDIO_DESC_IAD(/*_firstitf*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\ /* Standard AC Interface Descriptor(4.7.1) */\ @@ -567,7 +567,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb /* Output Terminal Descriptor(4.7.2.5) */\ TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ 0x03, /*_termtype*/ AUDIO_TERM_TYPE_OUT_DESKTOP_SPEAKER, /*_assocTerm*/ 0x01, /*_srcid*/ 0x02, /*_clkid*/ 0x04, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00),\ /* Feature Unit Descriptor(4.7.2.8) */\ - TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL(/*_unitid*/ 0x02, /*_srcid*/ 0x01, /*_ctrlch0master*/ 0 * (AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS), /*_ctrlch1*/ 0 * (AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS), /*_stridx*/ 0x00),\ + TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL(/*_unitid*/ 0x02, /*_srcid*/ 0x01, /*_ctrlch0master*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_stridx*/ 0x00),\ /* Standard AS Interface Descriptor(4.9.1) */\ /* Interface 1, Alternate 0 - default alternate setting with 0 bandwidth */\ TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x00),\ @@ -579,11 +579,11 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\ TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample),\ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\ - TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ 0x01),\ + TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epoutsize, /*_interval*/ 0x01),\ /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\ TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000),\ /* Standard AS Isochronous Feedback Endpoint Descriptor(4.10.2.1) */\ - TUD_AUDIO_DESC_STD_AS_ISO_FB_EP(/*_ep*/ _epfb, /*_interval*/ 1)\ + TUD_AUDIO_DESC_STD_AS_ISO_FB_EP(/*_ep*/ _epfb, /*_epsize*/ _epfbsize, /*_interval*/ 1) // Calculate wMaxPacketSize of Endpoints #define TUD_AUDIO_EP_SIZE(_maxFrequency, _nBytesPerSample, _nChannels) \ diff --git a/src/device/usbd_control.c b/src/device/usbd_control.c index 35cce1f7e..b1fd357aa 100644 --- a/src/device/usbd_control.c +++ b/src/device/usbd_control.c @@ -137,7 +137,7 @@ bool tud_control_xfer(uint8_t rhport, tusb_control_request_t const* request, voi void usbd_control_reset(void); void usbd_control_set_request(tusb_control_request_t const* request); void usbd_control_set_complete_callback(usbd_control_xfer_cb_t fp); -bool usbd_control_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); +bool usbd_control_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes); void usbd_control_reset(void) { tu_varclr(&_ctrl_xfer); diff --git a/src/host/usbh.c b/src/host/usbh.c index a94c22c4c..8c488aaa2 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -1421,6 +1421,9 @@ static void process_enumeration(tuh_xfer_t* xfer) { break; case ENUM_GET_DEVICE_DESC: { + // Allow 2ms for address recovery time, Ref USB Spec 9.2.6.3 + osal_task_delay(2); + uint8_t const new_addr = (uint8_t) tu_le16toh(xfer->setup->wValue); usbh_device_t* new_dev = get_device(new_addr); diff --git a/src/host/usbh.h b/src/host/usbh.h index 359684169..d0a5732e5 100644 --- a/src/host/usbh.h +++ b/src/host/usbh.h @@ -81,7 +81,7 @@ enum { }; typedef struct { - uint8_t max_nak; // max NAK per endpoint per frame + uint8_t max_nak; // max NAK per endpoint per frame to save CPU/SPI bus usage uint8_t cpuctl; // R16: CPU Control Register uint8_t pinctl; // R17: Pin Control Register. FDUPSPI bit is ignored } tuh_configure_max3421_t; diff --git a/src/osal/osal_freertos.h b/src/osal/osal_freertos.h index f1f05f353..a3a0f3a3f 100644 --- a/src/osal/osal_freertos.h +++ b/src/osal/osal_freertos.h @@ -78,7 +78,7 @@ typedef struct // _int_set is not used with an RTOS #define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \ static _type _name##_##buf[_depth];\ - osal_queue_def_t _name = { .depth = _depth, .item_sz = sizeof(_type), .buf = _name##_##buf, _OSAL_Q_NAME(_name) }; + osal_queue_def_t _name = { .depth = _depth, .item_sz = sizeof(_type), .buf = _name##_##buf, _OSAL_Q_NAME(_name) } //--------------------------------------------------------------------+ // TASK API diff --git a/src/portable/analog/max3421/hcd_max3421.c b/src/portable/analog/max3421/hcd_max3421.c index d9b8e1fc3..215feb481 100644 --- a/src/portable/analog/max3421/hcd_max3421.c +++ b/src/portable/analog/max3421/hcd_max3421.c @@ -168,14 +168,14 @@ enum { }; enum { - MAX_NAK_DEFAULT = 1 // Number of NAK per endpoint per usb frame + MAX_NAK_DEFAULT = 1 // Number of NAK per endpoint per usb frame to save CPU/SPI bus usage }; enum { EP_STATE_IDLE = 0, EP_STATE_COMPLETE = 1, EP_STATE_ABORTING = 2, - EP_STATE_ATTEMPT_1 = 3, // pending 1st attempt + EP_STATE_ATTEMPT_1 = 3, // Number of attempts to transfer in a frame. Incremented after each NAK EP_STATE_ATTEMPT_MAX = 15 }; @@ -183,17 +183,20 @@ enum { // //--------------------------------------------------------------------+ +typedef struct TU_ATTR_PACKED { + uint8_t ep_num : 4; + uint8_t is_setup : 1; + uint8_t is_out : 1; + uint8_t is_iso : 1; +} hxfr_bm_t; + +TU_VERIFY_STATIC(sizeof(hxfr_bm_t) == 1, "size is not correct"); + typedef struct { uint8_t daddr; - union { ; - struct TU_ATTR_PACKED { - uint8_t ep_num : 4; - uint8_t is_setup : 1; - uint8_t is_out : 1; - uint8_t is_iso : 1; - }hxfr_bm; - + union { + hxfr_bm_t hxfr_bm; uint8_t hxfr; }; @@ -219,7 +222,16 @@ typedef struct { uint8_t hien; uint8_t mode; uint8_t peraddr; - uint8_t hxfr; + union { + hxfr_bm_t hxfr_bm; + uint8_t hxfr; + }; + + // owner of data in SNDFIFO, for retrying NAKed without re-writing to FIFO + struct { + uint8_t daddr; + uint8_t hxfr; + }sndfifo_owner; atomic_flag busy; // busy transferring @@ -317,33 +329,9 @@ bool tuh_max3421_reg_write(uint8_t rhport, uint8_t reg, uint8_t data, bool in_is return ret; } -static void fifo_write(uint8_t rhport, uint8_t reg, uint8_t const * buffer, uint16_t len, bool in_isr) { - uint8_t hirq; - reg |= CMDBYTE_WRITE; - - max3421_spi_lock(rhport, in_isr); - - tuh_max3421_spi_xfer_api(rhport, ®, &hirq, 1); - _hcd_data.hirq = hirq; - tuh_max3421_spi_xfer_api(rhport, buffer, NULL, len); - - max3421_spi_unlock(rhport, in_isr); -} - -static void fifo_read(uint8_t rhport, uint8_t * buffer, uint16_t len, bool in_isr) { - uint8_t hirq; - uint8_t const reg = RCVVFIFO_ADDR; - - max3421_spi_lock(rhport, in_isr); - - tuh_max3421_spi_xfer_api(rhport, ®, &hirq, 1); - _hcd_data.hirq = hirq; - tuh_max3421_spi_xfer_api(rhport, NULL, buffer, len); - - max3421_spi_unlock(rhport, in_isr); -} - -//------------- register write helper -------------// +//-------------------------------------------------------------------- +// Register helper +//-------------------------------------------------------------------- TU_ATTR_ALWAYS_INLINE static inline void hirq_write(uint8_t rhport, uint8_t data, bool in_isr) { reg_write(rhport, HIRQ_ADDR, data, in_isr); // HIRQ write 1 is clear @@ -377,6 +365,47 @@ TU_ATTR_ALWAYS_INLINE static inline void sndbc_write(uint8_t rhport, uint8_t dat reg_write(rhport, SNDBC_ADDR, data, in_isr); } +//-------------------------------------------------------------------- +// FIFO access (receive, send, setup) +//-------------------------------------------------------------------- +static void hwfifo_write(uint8_t rhport, uint8_t reg, const uint8_t* buffer, uint8_t len, bool in_isr) { + uint8_t hirq; + reg |= CMDBYTE_WRITE; + + max3421_spi_lock(rhport, in_isr); + + tuh_max3421_spi_xfer_api(rhport, ®, &hirq, 1); + _hcd_data.hirq = hirq; + tuh_max3421_spi_xfer_api(rhport, buffer, NULL, len); + + max3421_spi_unlock(rhport, in_isr); +} + +// Write to SNDFIFO if len > 0 and update SNDBC +TU_ATTR_ALWAYS_INLINE static inline void hwfifo_send(uint8_t rhport, const uint8_t* buffer, uint8_t len, bool in_isr) { + if (len) { + hwfifo_write(rhport, SNDFIFO_ADDR, buffer, len, in_isr); + } + sndbc_write(rhport, len, in_isr); +} + +TU_ATTR_ALWAYS_INLINE static inline void hwfifo_setup(uint8_t rhport, const uint8_t* buffer, bool in_isr) { + hwfifo_write(rhport, SUDFIFO_ADDR, buffer, 8, in_isr); +} + +static void hwfifo_receive(uint8_t rhport, uint8_t * buffer, uint16_t len, bool in_isr) { + uint8_t hirq; + uint8_t const reg = RCVVFIFO_ADDR; + + max3421_spi_lock(rhport, in_isr); + + tuh_max3421_spi_xfer_api(rhport, ®, &hirq, 1); + _hcd_data.hirq = hirq; + tuh_max3421_spi_xfer_api(rhport, NULL, buffer, len); + + max3421_spi_unlock(rhport, in_isr); +} + //--------------------------------------------------------------------+ // Endpoint helper //--------------------------------------------------------------------+ @@ -417,7 +446,7 @@ static void free_ep(uint8_t daddr) { } } -// Check if endpoint has an queued transfer and not reach max NAK +// Check if endpoint has a queued transfer and not reach max NAK in this frame TU_ATTR_ALWAYS_INLINE static inline bool is_ep_pending(max3421_ep_t const * ep) { uint8_t const state = ep->state; return ep->packet_size && (state >= EP_STATE_ATTEMPT_1) && @@ -487,6 +516,7 @@ bool hcd_init(uint8_t rhport) { reg_write(rhport, PINCTL_ADDR, _tuh_cfg.pinctl | PINCTL_FDUPSPI, false); // v1 is 0x01, v2 is 0x12, v3 is 0x13 + // Note: v1 and v2 has host OUT errata whose workaround is not implemented in this driver uint8_t const revision = reg_read(rhport, REVISION_ADDR, false); TU_LOG2_HEX(revision); TU_ASSERT(revision == 0x01 || revision == 0x12 || revision == 0x13, false); @@ -615,22 +645,45 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t daddr, tusb_desc_endpoint_t const * e return true; } +/* The microcontroller repeatedly writes the SNDFIFO register R2 to load the FIFO with up to 64 data bytes. + * Then the microcontroller writes the SNDBC register, which this does three things: + * 1. Tells the MAX3421E SIE (Serial Interface Engine) how many bytes in the FIFO to send. + * 2. Connects the SNDFIFO and SNDBC register to the USB logic for USB transmission. + * 3. Clears the SNDBAVIRQ interrupt flag. If the second FIFO is available for µC loading, the SNDBAVIRQ immediately re-asserts. + + +-----------+ + --->| SNDBC-A | + / | SNDFIFO-A | + / +-----------+ + +------+ +-------------+ / +----------+ + | MCU |------>| R2: SNDFIFO |---- << Write R7 Flip >> ---| MAX3241E | + |(hcd) | | R7: SNDBC | / | SIE | + +------+ +-------------+ / +----------+ + +-----------+ / + | SNDBC-B | / + | SNDFIFO-B |<--- + +-----------+ + Note: xact_out() is called when starting a new transfer, continue a transfer (isr) or retry a transfer (NAK) + For NAK retry, we do not need to write to FIFO or SNDBC register again. +*/ static void xact_out(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) { // Page 12: Programming BULK-OUT Transfers - // TODO double buffered + // TODO: double buffering for ISO transfer if (switch_ep) { peraddr_write(rhport, ep->daddr, in_isr); - - uint8_t const hctl = (ep->data_toggle ? HCTL_SNDTOG1 : HCTL_SNDTOG0); + const uint8_t hctl = (ep->data_toggle ? HCTL_SNDTOG1 : HCTL_SNDTOG0); reg_write(rhport, HCTL_ADDR, hctl, in_isr); } - uint8_t const xact_len = (uint8_t) tu_min16(ep->total_len - ep->xferred_len, ep->packet_size); - TU_ASSERT(_hcd_data.hirq & HIRQ_SNDBAV_IRQ,); - if (xact_len) { - fifo_write(rhport, SNDFIFO_ADDR, ep->buf, xact_len, in_isr); + // Only write to sndfifo and sdnbc register if it is not a NAKed retry + if (!(ep->daddr == _hcd_data.sndfifo_owner.daddr && ep->hxfr == _hcd_data.sndfifo_owner.hxfr)) { + // skip SNDBAV IRQ check, overwrite sndfifo if needed + const uint8_t xact_len = (uint8_t) tu_min16(ep->total_len - ep->xferred_len, ep->packet_size); + hwfifo_send(rhport, ep->buf, xact_len, in_isr); } - sndbc_write(rhport, xact_len, in_isr); + _hcd_data.sndfifo_owner.daddr = ep->daddr; + _hcd_data.sndfifo_owner.hxfr = ep->hxfr; + hxfr_write(rhport, ep->hxfr, in_isr); } @@ -648,7 +701,7 @@ static void xact_in(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_is static void xact_setup(uint8_t rhport, max3421_ep_t *ep, bool in_isr) { peraddr_write(rhport, ep->daddr, in_isr); - fifo_write(rhport, SUDFIFO_ADDR, ep->buf, 8, in_isr); + hwfifo_setup(rhport, ep->buf, in_isr); hxfr_write(rhport, HXFR_SETUP, in_isr); } @@ -662,7 +715,7 @@ static void xact_generic(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool // status if (ep->buf == NULL || ep->total_len == 0) { - uint8_t const hxfr = (uint8_t) (HXFR_HS | (ep->hxfr & HXFR_OUT_NIN)); + const uint8_t hxfr = (uint8_t) (HXFR_HS | (ep->hxfr & HXFR_OUT_NIN)); peraddr_write(rhport, ep->daddr, in_isr); hxfr_write(rhport, hxfr, in_isr); return; @@ -823,11 +876,11 @@ static void xfer_complete_isr(uint8_t rhport, max3421_ep_t *ep, xfer_result_t re } static void handle_xfer_done(uint8_t rhport, bool in_isr) { - uint8_t const hrsl = reg_read(rhport, HRSL_ADDR, in_isr); - uint8_t const hresult = hrsl & HRSL_RESULT_MASK; - uint8_t const ep_num = _hcd_data.hxfr & HXFR_EPNUM_MASK; - uint8_t const hxfr_type = _hcd_data.hxfr & 0xf0; - uint8_t const ep_dir = ((hxfr_type & HXFR_SETUP) || (hxfr_type & HXFR_OUT_NIN)) ? 0 : 1; + const uint8_t hrsl = reg_read(rhport, HRSL_ADDR, in_isr); + const uint8_t hresult = hrsl & HRSL_RESULT_MASK; + const uint8_t ep_num = _hcd_data.hxfr_bm.ep_num; + const uint8_t hxfr_type = _hcd_data.hxfr & 0xf0; + const uint8_t ep_dir = ((hxfr_type & HXFR_SETUP) || (hxfr_type & HXFR_OUT_NIN)) ? 0 : 1; max3421_ep_t *ep = find_opened_ep(_hcd_data.peraddr, ep_num, ep_dir); TU_VERIFY(ep, ); @@ -842,7 +895,8 @@ static void handle_xfer_done(uint8_t rhport, bool in_isr) { // control endpoint -> retry immediately and return hxfr_write(rhport, _hcd_data.hxfr, in_isr); return; - } else if (EP_STATE_ATTEMPT_1 <= ep->state && ep->state < EP_STATE_ATTEMPT_MAX) { + } + if (EP_STATE_ATTEMPT_1 <= ep->state && ep->state < EP_STATE_ATTEMPT_MAX) { ep->state++; } } @@ -853,7 +907,6 @@ static void handle_xfer_done(uint8_t rhport, bool in_isr) { hxfr_write(rhport, _hcd_data.hxfr, in_isr); } else if (next_ep) { // switch to next pending endpoint - // TODO could have issue with double buffered if not clear previously out data xact_generic(rhport, next_ep, true, in_isr); } else { // no more pending in this frame -> clear busy @@ -896,11 +949,15 @@ static void handle_xfer_done(uint8_t rhport, bool in_isr) { if (ep->state == EP_STATE_COMPLETE) { xfer_complete_isr(rhport, ep, xfer_result, hrsl, in_isr); }else { - // more to transfer - hxfr_write(rhport, _hcd_data.hxfr, in_isr); + hxfr_write(rhport, _hcd_data.hxfr, in_isr); // more to transfer } } else { // SETUP or OUT transfer + + // clear sndfifo owner since data is sent + _hcd_data.sndfifo_owner.daddr = 0xff; + _hcd_data.sndfifo_owner.hxfr = 0xff; + uint8_t xact_len; if (hxfr_type & HXFR_SETUP) { @@ -917,8 +974,7 @@ static void handle_xfer_done(uint8_t rhport, bool in_isr) { if (xact_len < ep->packet_size || ep->xferred_len >= ep->total_len) { xfer_complete_isr(rhport, ep, xfer_result, hrsl, in_isr); } else { - // more to transfer - xact_out(rhport, ep, false, in_isr); + xact_out(rhport, ep, false, in_isr); // more to transfer } } } @@ -978,16 +1034,16 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) { // not call this handler again. So we need to loop until all IRQ are cleared while (hirq & (HIRQ_RCVDAV_IRQ | HIRQ_HXFRDN_IRQ)) { if (hirq & HIRQ_RCVDAV_IRQ) { - uint8_t const ep_num = _hcd_data.hxfr & HXFR_EPNUM_MASK; + const uint8_t ep_num = _hcd_data.hxfr_bm.ep_num; max3421_ep_t* ep = find_opened_ep(_hcd_data.peraddr, ep_num, 1); uint8_t xact_len = 0; // RCVDAV_IRQ can trigger 2 times (dual buffered) while (hirq & HIRQ_RCVDAV_IRQ) { - uint8_t rcvbc = reg_read(rhport, RCVBC_ADDR, in_isr); + const uint8_t rcvbc = reg_read(rhport, RCVBC_ADDR, in_isr); xact_len = (uint8_t) tu_min16(rcvbc, ep->total_len - ep->xferred_len); if (xact_len) { - fifo_read(rhport, ep->buf, xact_len, in_isr); + hwfifo_receive(rhport, ep->buf, xact_len, in_isr); ep->buf += xact_len; ep->xferred_len += xact_len; } diff --git a/src/portable/espressif/esp32sx/dcd_esp32sx.c b/src/portable/espressif/esp32sx/dcd_esp32sx.c index f912bef89..61911ab4c 100644 --- a/src/portable/espressif/esp32sx/dcd_esp32sx.c +++ b/src/portable/espressif/esp32sx/dcd_esp32sx.c @@ -207,6 +207,7 @@ void dcd_init(uint8_t rhport) USB_USBRSTMSK_M | USB_ENUMDONEMSK_M | USB_RESETDETMSK_M | + USB_WKUPINT_M | USB_DISCONNINTMSK_M; // host most only dcd_connect(rhport); diff --git a/src/portable/mentor/musb/dcd_musb.c b/src/portable/mentor/musb/dcd_musb.c index a817c5d6e..a40b3dc07 100644 --- a/src/portable/mentor/musb/dcd_musb.c +++ b/src/portable/mentor/musb/dcd_musb.c @@ -2,6 +2,7 @@ * The MIT License (MIT) * * Copyright (c) 2021 Koji KITAYAMA + * Copyright (c) 2024, Brent Kowal (Analog Devices, Inc) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -26,8 +27,10 @@ #include "tusb_option.h" -#if CFG_TUD_ENABLED && \ - TU_CHECK_MCU(OPT_MCU_MSP432E4, OPT_MCU_TM4C123, OPT_MCU_TM4C129) +#if CFG_TUD_ENABLED && defined(TUP_USBIP_MUSB) + +#define MUSB_DEBUG 2 +#define MUSB_REGS(rhport) ((musb_regs_t*) MUSB_BASES[rhport]) #if __GNUC__ > 8 && defined(__ARM_FEATURE_UNALIGNED) /* GCC warns that an address may be unaligned, even though @@ -35,48 +38,30 @@ _Pragma("GCC diagnostic ignored \"-Waddress-of-packed-member\""); #endif +#include "musb_type.h" #include "device/dcd.h" -#if TU_CHECK_MCU(OPT_MCU_MSP432E4) - #include "musb_msp432e.h" - -#elif TU_CHECK_MCU(OPT_MCU_TM4C123, OPT_MCU_TM4C129) - #include "musb_tm4c.h" - - // HACK generalize later - #include "musb_type.h" - #define FIFO0_WORD FIFO0 - #define FIFO1_WORD FIFO1 - +// Following symbols must be defined by port header +// - musb_dcd_int_enable/disable/clear/get_enable +// - musb_dcd_int_handler_enter/exit +#if defined(TUP_USBIP_MUSB_TI) + #include "musb_ti.h" +#elif defined(TUP_USBIP_MUSB_ADI) + #include "musb_max32.h" #else - #error "Unsupported MCUs" + #error "Unsupported MCU" #endif /*------------------------------------------------------------------ * MACRO TYPEDEF CONSTANT ENUM DECLARATION *------------------------------------------------------------------*/ -#define REQUEST_TYPE_INVALID (0xFFu) -typedef struct { - uint_fast16_t beg; /* offset of including first element */ - uint_fast16_t end; /* offset of excluding the last element */ -} free_block_t; - -typedef struct TU_ATTR_PACKED { - uint16_t TXMAXP; - uint8_t TXCSRL; - uint8_t TXCSRH; - uint16_t RXMAXP; - uint8_t RXCSRL; - uint8_t RXCSRH; - uint16_t RXCOUNT; - uint16_t RESERVED[3]; -} hw_endpoint_t; +#define REQUEST_TYPE_INVALID (0xFFu) typedef union { - uint8_t u8; - uint16_t u16; - uint32_t u32; + volatile uint8_t u8; + volatile uint16_t u16; + volatile uint32_t u32; } hw_fifo_t; typedef struct TU_ATTR_PACKED @@ -92,134 +77,97 @@ typedef struct uint16_t remaining_ctrl; /* The number of bytes remaining in data stage of control transfer. */ int8_t status_out; pipe_state_t pipe0; - pipe_state_t pipe[2][7]; /* pipe[direction][endpoint number - 1] */ + pipe_state_t pipe[2][TUP_DCD_ENDPOINT_MAX-1]; /* pipe[direction][endpoint number - 1] */ uint16_t pipe_buf_is_fifo[2]; /* Bitmap. Each bit means whether 1:TU_FIFO or 0:POD. */ } dcd_data_t; -/*------------------------------------------------------------------ - * INTERNAL OBJECT & FUNCTION DECLARATION - *------------------------------------------------------------------*/ static dcd_data_t _dcd; +//-------------------------------------------------------------------- +// HW FIFO Helper +// Note: Index register is already set by caller +//-------------------------------------------------------------------- -static inline free_block_t *find_containing_block(free_block_t *beg, free_block_t *end, uint_fast16_t addr) -{ - free_block_t *cur = beg; - for (; cur < end && ((addr < cur->beg) || (cur->end <= addr)); ++cur) ; - return cur; -} +#if MUSB_CFG_DYNAMIC_FIFO -static inline int update_free_block_list(free_block_t *blks, unsigned num, uint_fast16_t addr, uint_fast16_t size) -{ - free_block_t *p = find_containing_block(blks, blks + num, addr); - TU_ASSERT(p != blks + num, -2); - if (p->beg == addr) { - /* Shrink block */ - p->beg = addr + size; - if (p->beg != p->end) return 0; - /* remove block */ - free_block_t *end = blks + num; - while (p + 1 < end) { - *p = *(p + 1); - ++p; - } - return -1; - } else { - /* Split into 2 blocks */ - free_block_t tmp = { - .beg = addr + size, - .end = p->end - }; - p->end = addr; - if (p->beg == p->end) { - if (tmp.beg != tmp.end) { - *p = tmp; - return 0; - } - /* remove block */ - free_block_t *end = blks + num; - while (p + 1 < end) { - *p = *(p + 1); - ++p; - } - return -1; - } - if (tmp.beg == tmp.end) return 0; - blks[num] = tmp; - return 1; +// musb is configured to use dynamic FIFO sizing. +// FF Size is encodded: 1 << (fifo_size[3:0] + 3) = 8 << fifo_size[3:0] +// FF Address is 8*ff_addr[12:0] +// First 64 bytes are reserved for EP0 +static uint32_t alloced_fifo_bytes; + +// ffsize is log2(mps) - 3 (round up) +TU_ATTR_ALWAYS_INLINE static inline uint8_t hwfifo_byte2size(uint16_t nbytes) { + uint8_t ffsize = 28 - tu_min8(28, __builtin_clz(nbytes)); + if ((8u << ffsize) < nbytes) { + ++ffsize; } + return ffsize; } -static inline unsigned free_block_size(free_block_t const *blk) -{ - return blk->end - blk->beg; +TU_ATTR_ALWAYS_INLINE static inline void hwfifo_reset(musb_regs_t* musb, unsigned epnum, unsigned is_rx) { + (void) epnum; + musb->fifo_size[is_rx] = 0; + musb->fifo_addr[is_rx] = 0; } -#if 0 -static inline void print_block_list(free_block_t const *blk, unsigned num) -{ - TU_LOG1("*************\r\n"); - for (unsigned i = 0; i < num; ++i) { - TU_LOG1(" Blk%u %u %u\r\n", i, blk->beg, blk->end); - ++blk; +TU_ATTR_ALWAYS_INLINE static inline bool hwfifo_config(musb_regs_t* musb, unsigned epnum, unsigned is_rx, unsigned mps, + bool double_packet) { + (void) epnum; + uint8_t ffsize = hwfifo_byte2size(mps); + mps = 8 << ffsize; // round up to the next power of 2 + + if (double_packet) { + ffsize |= MUSB_FIFOSZ_DOUBLE_PACKET; + mps <<= 1; } + + TU_ASSERT(alloced_fifo_bytes + mps <= MUSB_CFG_DYNAMIC_FIFO_SIZE); + musb->fifo_addr[is_rx] = alloced_fifo_bytes / 8; + musb->fifo_size[is_rx] = ffsize; + + alloced_fifo_bytes += mps; + return true; } + #else -#define print_block_list(a,b) -#endif -static unsigned find_free_memory(uint_fast16_t size_in_log2_minus3) -{ - free_block_t free_blocks[2 * (TUP_DCD_ENDPOINT_MAX - 1)]; - unsigned num_blocks = 1; +TU_ATTR_ALWAYS_INLINE static inline void hwfifo_reset(musb_regs_t* musb, unsigned epnum, unsigned is_rx) { + (void) musb; (void) epnum; (void) is_rx; + // nothing to do for static FIFO +} - /* Initialize free memory block list */ - free_blocks[0].beg = 64 / 8; - free_blocks[0].end = (4 << 10) / 8; /* 4KiB / 8 bytes */ - for (int i = 1; i < TUP_DCD_ENDPOINT_MAX; ++i) { - uint_fast16_t addr; - int num; - USB0->EPIDX = i; - addr = USB0->TXFIFOADD; - if (addr) { - unsigned sz = USB0->TXFIFOSZ; - unsigned sft = (sz & USB_TXFIFOSZ_SIZE_M) + ((sz & USB_TXFIFOSZ_DPB) ? 1: 0); - num = update_free_block_list(free_blocks, num_blocks, addr, 1 << sft); - TU_ASSERT(-2 < num, 0); - num_blocks += num; - print_block_list(free_blocks, num_blocks); - } - addr = USB0->RXFIFOADD; - if (addr) { - unsigned sz = USB0->RXFIFOSZ; - unsigned sft = (sz & USB_RXFIFOSZ_SIZE_M) + ((sz & USB_RXFIFOSZ_DPB) ? 1: 0); - num = update_free_block_list(free_blocks, num_blocks, addr, 1 << sft); - TU_ASSERT(-2 < num, 0); - num_blocks += num; - print_block_list(free_blocks, num_blocks); +TU_ATTR_ALWAYS_INLINE static inline bool hwfifo_config(musb_regs_t* musb, unsigned epnum, unsigned is_rx, unsigned mps, + bool double_packet) { + (void) epnum; (void) mps; + if (!double_packet) { + #if defined(TUP_USBIP_MUSB_ADI) + musb->indexed_csr.maxp_csr[is_rx].csrh |= MUSB_CSRH_DISABLE_DOUBLE_PACKET(is_rx); + #else + if (is_rx) { + musb->rx_doulbe_packet_disable |= 1u << epnum; + } else { + musb->tx_double_packet_disable |= 1u << epnum; } + #endif } - print_block_list(free_blocks, num_blocks); - /* Find the best fit memory block */ - uint_fast16_t size_in_8byte_unit = 1 << size_in_log2_minus3; - free_block_t const *min = NULL; - uint_fast16_t min_sz = 0xFFFFu; - free_block_t const *end = &free_blocks[num_blocks]; - for (free_block_t const *cur = &free_blocks[0]; cur < end; ++cur) { - uint_fast16_t sz = free_block_size(cur); - if (sz < size_in_8byte_unit) continue; - if (size_in_8byte_unit == sz) return cur->beg; - if (sz < min_sz) min = cur; - } - TU_ASSERT(min, 0); - return min->beg; + return true; } -static inline volatile hw_endpoint_t* edpt_regs(unsigned epnum_minus1) -{ - volatile hw_endpoint_t *regs = (volatile hw_endpoint_t*)((uintptr_t)&USB0->TXMAXP1); - return regs + epnum_minus1; +#endif + +// Flush FIFO and clear data toggle +TU_ATTR_ALWAYS_INLINE static inline void hwfifo_flush(musb_regs_t* musb, unsigned epnum, unsigned is_rx, bool clear_dtog) { + (void) epnum; + const uint8_t csrl_dtog = clear_dtog ? MUSB_CSRL_CLEAR_DATA_TOGGLE(is_rx) : 0; + musb_ep_maxp_csr_t* maxp_csr = &musb->indexed_csr.maxp_csr[is_rx]; + // may need to flush twice for double packet + for (unsigned i=0; i<2; i++) { + if (maxp_csr->csrl & MUSB_CSRL_PACKET_READY(is_rx)) { + maxp_csr->csrl = MUSB_CSRL_FLUSH_FIFO(is_rx) | csrl_dtog; + } + } } static void pipe_write_packet(void *buf, volatile void *fifo, unsigned len) @@ -284,11 +232,14 @@ static void pipe_read_write_packet_ff(tu_fifo_t *f, volatile void *fifo, unsigne ops[dir].tu_fifo_advance(f, total_len - rem); } -static void process_setup_packet(uint8_t rhport) -{ +static void process_setup_packet(uint8_t rhport) { + musb_regs_t* musb_regs = MUSB_REGS(rhport); + + // Read setup packet uint32_t *p = (void*)&_dcd.setup_packet; - p[0] = USB0->FIFO0_WORD; - p[1] = USB0->FIFO0_WORD; + volatile uint32_t *fifo_ptr = &musb_regs->fifo[0]; + p[0] = *fifo_ptr; + p[1] = *fifo_ptr; _dcd.pipe0.buf = NULL; _dcd.pipe0.length = 0; @@ -299,12 +250,16 @@ static void process_setup_packet(uint8_t rhport) _dcd.remaining_ctrl = len; const unsigned dir_in = tu_edpt_dir(_dcd.setup_packet.bmRequestType); /* Clear RX FIFO and reverse the transaction direction */ - if (len && dir_in) USB0->CSRL0 = USB_CSRL0_RXRDYC; + if (len && dir_in) { + musb_ep_csr_t* ep_csr = get_ep_csr(musb_regs, 0); + ep_csr->csr0l = MUSB_CSRL0_RXRDYC; + } } -static bool handle_xfer_in(uint_fast8_t ep_addr) +static bool handle_xfer_in(uint8_t rhport, uint_fast8_t ep_addr) { - unsigned epnum_minus1 = tu_edpt_number(ep_addr) - 1; + unsigned epnum = tu_edpt_number(ep_addr); + unsigned epnum_minus1 = epnum - 1; pipe_state_t *pipe = &_dcd.pipe[tu_edpt_dir(ep_addr)][epnum_minus1]; const unsigned rem = pipe->remaining; @@ -313,44 +268,49 @@ static bool handle_xfer_in(uint_fast8_t ep_addr) return true; } - volatile hw_endpoint_t *regs = edpt_regs(epnum_minus1); - const unsigned mps = regs->TXMAXP; + musb_regs_t* musb_regs = MUSB_REGS(rhport); + musb_ep_csr_t* ep_csr = get_ep_csr(musb_regs, epnum); + const unsigned mps = ep_csr->tx_maxp; const unsigned len = TU_MIN(mps, rem); void *buf = pipe->buf; + volatile void *fifo_ptr = &musb_regs->fifo[epnum]; // TU_LOG1(" %p mps %d len %d rem %d\r\n", buf, mps, len, rem); if (len) { if (_dcd.pipe_buf_is_fifo[TUSB_DIR_IN] & TU_BIT(epnum_minus1)) { - pipe_read_write_packet_ff(buf, &USB0->FIFO1_WORD + epnum_minus1, len, TUSB_DIR_IN); + pipe_read_write_packet_ff(buf, fifo_ptr, len, TUSB_DIR_IN); } else { - pipe_write_packet(buf, &USB0->FIFO1_WORD + epnum_minus1, len); + pipe_write_packet(buf, fifo_ptr, len); pipe->buf = buf + len; } pipe->remaining = rem - len; } - regs->TXCSRL = USB_TXCSRL1_TXRDY; - // TU_LOG1(" TXCSRL%d = %x %d\r\n", epnum_minus1 + 1, regs->TXCSRL, rem - len); + ep_csr->tx_csrl = MUSB_TXCSRL1_TXRDY; + // TU_LOG1(" TXCSRL%d = %x %d\r\n", epnum, ep_csr->tx_csrl, rem - len); return false; } -static bool handle_xfer_out(uint_fast8_t ep_addr) +static bool handle_xfer_out(uint8_t rhport, uint_fast8_t ep_addr) { - unsigned epnum_minus1 = tu_edpt_number(ep_addr) - 1; + unsigned epnum = tu_edpt_number(ep_addr); + unsigned epnum_minus1 = epnum - 1; pipe_state_t *pipe = &_dcd.pipe[tu_edpt_dir(ep_addr)][epnum_minus1]; - volatile hw_endpoint_t *regs = edpt_regs(epnum_minus1); - // TU_LOG1(" RXCSRL%d = %x\r\n", epnum_minus1 + 1, regs->RXCSRL); + musb_regs_t* musb_regs = MUSB_REGS(rhport); + musb_ep_csr_t* ep_csr = get_ep_csr(musb_regs, epnum); + // TU_LOG1(" RXCSRL%d = %x\r\n", epnum_minus1 + 1, ep_csr->rx_csrl); - TU_ASSERT(regs->RXCSRL & USB_RXCSRL1_RXRDY); + TU_ASSERT(ep_csr->rx_csrl & MUSB_RXCSRL1_RXRDY); - const unsigned mps = regs->RXMAXP; + const unsigned mps = ep_csr->rx_maxp; const unsigned rem = pipe->remaining; - const unsigned vld = regs->RXCOUNT; + const unsigned vld = ep_csr->rx_count; const unsigned len = TU_MIN(TU_MIN(rem, mps), vld); void *buf = pipe->buf; + volatile void *fifo_ptr = &musb_regs->fifo[epnum]; if (len) { if (_dcd.pipe_buf_is_fifo[TUSB_DIR_OUT] & TU_BIT(epnum_minus1)) { - pipe_read_write_packet_ff(buf, &USB0->FIFO1_WORD + epnum_minus1, len, TUSB_DIR_OUT); + pipe_read_write_packet_ff(buf, fifo_ptr, len, TUSB_DIR_OUT); } else { - pipe_read_packet(buf, &USB0->FIFO1_WORD + epnum_minus1, len); + pipe_read_packet(buf, fifo_ptr, len); pipe->buf = buf + len; } pipe->remaining = rem - len; @@ -359,15 +319,14 @@ static bool handle_xfer_out(uint_fast8_t ep_addr) pipe->buf = NULL; return NULL != buf; } - regs->RXCSRL = 0; /* Clear RXRDY bit */ + ep_csr->rx_csrl = 0; /* Clear RXRDY bit */ return false; } static bool edpt_n_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes) { - (void)rhport; - - unsigned epnum_minus1 = tu_edpt_number(ep_addr) - 1; + unsigned epnum = tu_edpt_number(ep_addr); + unsigned epnum_minus1 = epnum - 1; unsigned dir_in = tu_edpt_dir(ep_addr); pipe_state_t *pipe = &_dcd.pipe[dir_in][epnum_minus1]; @@ -376,10 +335,11 @@ static bool edpt_n_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16 pipe->remaining = total_bytes; if (dir_in) { - handle_xfer_in(ep_addr); + handle_xfer_in(rhport, ep_addr); } else { - volatile hw_endpoint_t *regs = edpt_regs(epnum_minus1); - if (regs->RXCSRL & USB_RXCSRL1_RXRDY) regs->RXCSRL = 0; + musb_regs_t* musb_regs = MUSB_REGS(rhport); + musb_ep_csr_t* ep_csr = get_ep_csr(musb_regs, epnum); + if (ep_csr->rx_csrl & MUSB_RXCSRL1_RXRDY) ep_csr->rx_csrl = 0; } return true; } @@ -388,7 +348,8 @@ static bool edpt0_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_ { (void)rhport; TU_ASSERT(total_bytes <= 64); /* Current implementation supports for only up to 64 bytes. */ - + musb_regs_t* musb_regs = MUSB_REGS(rhport); + musb_ep_csr_t* ep_csr = get_ep_csr(musb_regs, 0); const unsigned req = _dcd.setup_packet.bmRequestType; TU_ASSERT(req != REQUEST_TYPE_INVALID || total_bytes == 0); @@ -399,7 +360,7 @@ static bool edpt0_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_ * may have already finished and received the next setup packet * without calling this function, so we have no choice but to * invoke the callback function of status packet here. */ - // TU_LOG1(" STATUS OUT USB0->CSRL0 = %x\r\n", USB0->CSRL0); + // TU_LOG1(" STATUS OUT ep_csr->csr0l = %x\r\n", ep_csr->csr0l); _dcd.status_out = 0; if (req == REQUEST_TYPE_INVALID) { dcd_event_xfer_complete(rhport, ep_addr, total_bytes, XFER_RESULT_SUCCESS, false); @@ -415,8 +376,9 @@ static bool edpt0_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_ TU_ASSERT(total_bytes <= _dcd.remaining_ctrl); const unsigned rem = _dcd.remaining_ctrl; const unsigned len = TU_MIN(TU_MIN(rem, 64), total_bytes); + volatile void *fifo_ptr = &musb_regs->fifo[0]; if (dir_in) { - pipe_write_packet(buffer, &USB0->FIFO0_WORD, len); + pipe_write_packet(buffer, fifo_ptr, len); _dcd.pipe0.buf = buffer + len; _dcd.pipe0.length = len; @@ -427,45 +389,48 @@ static bool edpt0_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_ _dcd.setup_packet.bmRequestType = REQUEST_TYPE_INVALID; /* Change to STATUS/SETUP stage */ _dcd.status_out = 1; /* Flush TX FIFO and reverse the transaction direction. */ - USB0->CSRL0 = USB_CSRL0_TXRDY | USB_CSRL0_DATAEND; + ep_csr->csr0l = MUSB_CSRL0_TXRDY | MUSB_CSRL0_DATAEND; } else { - USB0->CSRL0 = USB_CSRL0_TXRDY; /* Flush TX FIFO to return ACK. */ + ep_csr->csr0l = MUSB_CSRL0_TXRDY; /* Flush TX FIFO to return ACK. */ } - // TU_LOG1(" IN USB0->CSRL0 = %x\r\n", USB0->CSRL0); + // TU_LOG1(" IN ep_csr->csr0l = %x\r\n", ep_csr->csr0l); } else { - // TU_LOG1(" OUT USB0->CSRL0 = %x\r\n", USB0->CSRL0); + // TU_LOG1(" OUT ep_csr->csr0l = %x\r\n", ep_csr->csr0l); _dcd.pipe0.buf = buffer; _dcd.pipe0.length = len; _dcd.pipe0.remaining = len; - USB0->CSRL0 = USB_CSRL0_RXRDYC; /* Clear RX FIFO to return ACK. */ + ep_csr->csr0l = MUSB_CSRL0_RXRDYC; /* Clear RX FIFO to return ACK. */ } } else if (dir_in) { - // TU_LOG1(" STATUS IN USB0->CSRL0 = %x\r\n", USB0->CSRL0); + // TU_LOG1(" STATUS IN ep_csr->csr0l = %x\r\n", ep_csr->csr0l); _dcd.pipe0.buf = NULL; _dcd.pipe0.length = 0; _dcd.pipe0.remaining = 0; /* Clear RX FIFO and reverse the transaction direction */ - USB0->CSRL0 = USB_CSRL0_RXRDYC | USB_CSRL0_DATAEND; + ep_csr->csr0l = MUSB_CSRL0_RXRDYC | MUSB_CSRL0_DATAEND; } return true; } static void process_ep0(uint8_t rhport) { - uint_fast8_t csrl = USB0->CSRL0; + musb_regs_t* musb_regs = MUSB_REGS(rhport); + musb_ep_csr_t* ep_csr = get_ep_csr(musb_regs, 0); + uint_fast8_t csrl = ep_csr->csr0l; - // TU_LOG1(" EP0 USB0->CSRL0 = %x\r\n", csrl); + // TU_LOG1(" EP0 ep_csr->csr0l = %x\r\n", csrl); + // 21.1.5: endpoint 0 service routine as peripheral - if (csrl & USB_CSRL0_STALLED) { + if (csrl & MUSB_CSRL0_STALLED) { /* Returned STALL packet to HOST. */ - USB0->CSRL0 = 0; /* Clear STALL */ + ep_csr->csr0l = 0; /* Clear STALL */ return; } unsigned req = _dcd.setup_packet.bmRequestType; - if (csrl & USB_CSRL0_SETEND) { + if (csrl & MUSB_CSRL0_SETEND) { TU_LOG1(" ABORT by the next packets\r\n"); - USB0->CSRL0 = USB_CSRL0_SETENDC; + ep_csr->csr0l = MUSB_CSRL0_SETENDC; if (req != REQUEST_TYPE_INVALID && _dcd.pipe0.buf) { /* DATA stage was aborted by receiving STATUS or SETUP packet. */ _dcd.pipe0.buf = NULL; @@ -476,23 +441,24 @@ static void process_ep0(uint8_t rhport) XFER_RESULT_SUCCESS, true); } req = REQUEST_TYPE_INVALID; - if (!(csrl & USB_CSRL0_RXRDY)) return; /* Received SETUP packet */ + if (!(csrl & MUSB_CSRL0_RXRDY)) return; /* Received SETUP packet */ } - if (csrl & USB_CSRL0_RXRDY) { + if (csrl & MUSB_CSRL0_RXRDY) { /* Received SETUP or DATA OUT packet */ if (req == REQUEST_TYPE_INVALID) { /* SETUP */ - TU_ASSERT(sizeof(tusb_control_request_t) == USB0->COUNT0,); + TU_ASSERT(sizeof(tusb_control_request_t) == ep_csr->count0,); process_setup_packet(rhport); return; } if (_dcd.pipe0.buf) { /* DATA OUT */ - const unsigned vld = USB0->COUNT0; + const unsigned vld = ep_csr->count0; const unsigned rem = _dcd.pipe0.remaining; const unsigned len = TU_MIN(TU_MIN(rem, 64), vld); - pipe_read_packet(_dcd.pipe0.buf, &USB0->FIFO0_WORD, len); + volatile void *fifo_ptr = &musb_regs->fifo[0]; + pipe_read_packet(_dcd.pipe0.buf, fifo_ptr, len); _dcd.pipe0.remaining = rem - len; _dcd.remaining_ctrl -= len; @@ -512,7 +478,7 @@ static void process_ep0(uint8_t rhport) /* STATUS IN */ if (*(const uint16_t*)(uintptr_t)&_dcd.setup_packet == 0x0500) { /* The address must be changed on completion of the control transfer. */ - USB0->FADDR = (uint8_t)_dcd.setup_packet.wValue; + musb_regs->faddr = (uint8_t)_dcd.setup_packet.wValue; } _dcd.setup_packet.bmRequestType = REQUEST_TYPE_INVALID; dcd_event_xfer_complete(rhport, @@ -534,118 +500,147 @@ static void process_ep0(uint8_t rhport) static void process_edpt_n(uint8_t rhport, uint_fast8_t ep_addr) { bool completed; - const unsigned dir_in = tu_edpt_dir(ep_addr); - const unsigned epn_minus1 = tu_edpt_number(ep_addr) - 1; + const unsigned dir_in = tu_edpt_dir(ep_addr); + const unsigned epn = tu_edpt_number(ep_addr); + const unsigned epn_minus1 = epn - 1; - volatile hw_endpoint_t *regs = edpt_regs(epn_minus1); + musb_regs_t* musb_regs = MUSB_REGS(rhport); + musb_ep_csr_t* ep_csr = get_ep_csr(musb_regs, epn); if (dir_in) { - // TU_LOG1(" TXCSRL%d = %x\r\n", epn_minus1 + 1, regs->TXCSRL); - if (regs->TXCSRL & USB_TXCSRL1_STALLED) { - regs->TXCSRL &= ~(USB_TXCSRL1_STALLED | USB_TXCSRL1_UNDRN); + // TU_LOG1(" TX CSRL%d = %x\r\n", epn, ep_csr->tx_csrl); + if (ep_csr->tx_csrl & MUSB_TXCSRL1_STALLED) { + ep_csr->tx_csrl &= ~(MUSB_TXCSRL1_STALLED | MUSB_TXCSRL1_UNDRN); return; } - completed = handle_xfer_in(ep_addr); + completed = handle_xfer_in(rhport, ep_addr); } else { - // TU_LOG1(" RXCSRL%d = %x\r\n", epn_minus1 + 1, regs->RXCSRL); - if (regs->RXCSRL & USB_RXCSRL1_STALLED) { - regs->RXCSRL &= ~(USB_RXCSRL1_STALLED | USB_RXCSRL1_OVER); + // TU_LOG1(" RX CSRL%d = %x\r\n", epn, ep_csr->rx_csrl); + if (ep_csr->rx_csrl & MUSB_RXCSRL1_STALLED) { + ep_csr->rx_csrl &= ~(MUSB_RXCSRL1_STALLED | MUSB_RXCSRL1_OVER); return; } - completed = handle_xfer_out(ep_addr); + completed = handle_xfer_out(rhport, ep_addr); } if (completed) { - pipe_state_t *pipe = &_dcd.pipe[dir_in][tu_edpt_number(ep_addr) - 1]; + pipe_state_t *pipe = &_dcd.pipe[dir_in][epn_minus1]; dcd_event_xfer_complete(rhport, ep_addr, pipe->length - pipe->remaining, XFER_RESULT_SUCCESS, true); } } -static void process_bus_reset(uint8_t rhport) -{ - /* When bmRequestType is REQUEST_TYPE_INVALID(0xFF), - * a control transfer state is SETUP or STATUS stage. */ +// Upon BUS RESET is detected, hardware havs already done: +// faddr = 0, index = 0, flushes all ep fifos, clears all ep csr, enabled all ep interrupts +static void process_bus_reset(uint8_t rhport) { + musb_regs_t* musb = MUSB_REGS(rhport); + +#if MUSB_CFG_DYNAMIC_FIFO + alloced_fifo_bytes = CFG_TUD_ENDPOINT0_SIZE; +#endif + + /* When bmRequestType is REQUEST_TYPE_INVALID(0xFF), a control transfer state is SETUP or STATUS stage. */ _dcd.setup_packet.bmRequestType = REQUEST_TYPE_INVALID; _dcd.status_out = 0; /* When pipe0.buf has not NULL, DATA stage works in progress. */ _dcd.pipe0.buf = NULL; - USB0->TXIE = 1; /* Enable only EP0 */ - USB0->RXIE = 0; + musb->intr_txen = 1; /* Enable only EP0 */ + musb->intr_rxen = 0; /* Clear FIFO settings */ for (unsigned i = 1; i < TUP_DCD_ENDPOINT_MAX; ++i) { - USB0->EPIDX = i; - USB0->TXFIFOSZ = 0; - USB0->TXFIFOADD = 0; - USB0->RXFIFOSZ = 0; - USB0->RXFIFOADD = 0; + musb->index = i; + hwfifo_reset(musb, i, 0); + hwfifo_reset(musb, i, 1); } - dcd_event_bus_reset(rhport, TUSB_SPEED_FULL, true); + dcd_event_bus_reset(rhport, (musb->power & MUSB_POWER_HSMODE) ? TUSB_SPEED_HIGH : TUSB_SPEED_FULL, true); } /*------------------------------------------------------------------ * Device API *------------------------------------------------------------------*/ -void dcd_init(uint8_t rhport) -{ - (void)rhport; - USB0->IE |= USB_IE_SUSPND; - NVIC_ClearPendingIRQ(USB0_IRQn); +#if CFG_TUSB_DEBUG >= MUSB_DEBUG +void print_musb_info(musb_regs_t* musb_regs) { + // print version, epinfo, raminfo, config_data0, fifo_size + TU_LOG1("musb version = %u.%u\r\n", musb_regs->hwvers_bit.major, musb_regs->hwvers_bit.minor); + TU_LOG1("Number of endpoints: %u TX, %u RX\r\n", musb_regs->epinfo_bit.tx_ep_num, musb_regs->epinfo_bit.rx_ep_num); + TU_LOG1("RAM Info: %u DMA Channel, %u RAM address width\r\n", musb_regs->raminfo_bit.dma_channel, musb_regs->raminfo_bit.ram_bits); + + musb_regs->index = 0; + TU_LOG1("config_data0 = 0x%x\r\n", musb_regs->indexed_csr.config_data0); +#if MUSB_CFG_DYNAMIC_FIFO + TU_LOG1("Dynamic FIFO configuration\r\n"); +#else + for (uint8_t i=1; i <= musb_regs->epinfo_bit.tx_ep_num; i++) { + musb_regs->index = i; + TU_LOG1("FIFO %u Size: TX %u RX %u\r\n", i, musb_regs->indexed_csr.fifo_size_bit.tx, musb_regs->indexed_csr.fifo_size_bit.rx); + } +#endif +} +#endif + +void dcd_init(uint8_t rhport) { + musb_regs_t* musb_regs = MUSB_REGS(rhport); + +#if CFG_TUSB_DEBUG >= MUSB_DEBUG + print_musb_info(musb_regs); +#endif + + musb_regs->intr_usben |= MUSB_IE_SUSPND; + musb_dcd_int_clear(rhport); + musb_dcd_phy_init(rhport); dcd_connect(rhport); } -void dcd_int_enable(uint8_t rhport) -{ - (void)rhport; - NVIC_EnableIRQ(USB0_IRQn); +void dcd_int_enable(uint8_t rhport) { + musb_dcd_int_enable(rhport); } -void dcd_int_disable(uint8_t rhport) -{ - (void)rhport; - NVIC_DisableIRQ(USB0_IRQn); +void dcd_int_disable(uint8_t rhport) { + musb_dcd_int_disable(rhport); } // Receive Set Address request, mcu port must also include status IN response void dcd_set_address(uint8_t rhport, uint8_t dev_addr) { - (void)rhport; (void)dev_addr; + musb_regs_t* musb_regs = MUSB_REGS(rhport); + musb_ep_csr_t* ep_csr = get_ep_csr(musb_regs, 0); + _dcd.pipe0.buf = NULL; _dcd.pipe0.length = 0; _dcd.pipe0.remaining = 0; /* Clear RX FIFO to return ACK. */ - USB0->CSRL0 = USB_CSRL0_RXRDYC | USB_CSRL0_DATAEND; + ep_csr->csr0l = MUSB_CSRL0_RXRDYC | MUSB_CSRL0_DATAEND; } // Wake up host -void dcd_remote_wakeup(uint8_t rhport) -{ - (void)rhport; - USB0->POWER |= USB_POWER_RESUME; +void dcd_remote_wakeup(uint8_t rhport) { + musb_regs_t* musb_regs = MUSB_REGS(rhport); + musb_regs->power |= MUSB_POWER_RESUME; unsigned cnt = SystemCoreClock / 1000; while (cnt--) __NOP(); - USB0->POWER &= ~USB_POWER_RESUME; + musb_regs->power &= ~MUSB_POWER_RESUME; } // Connect by enabling internal pull-up resistor on D+/D- void dcd_connect(uint8_t rhport) { - (void)rhport; - USB0->POWER |= USB_POWER_SOFTCONN; + musb_regs_t* musb_regs = MUSB_REGS(rhport); + musb_regs->power |= TUD_OPT_HIGH_SPEED ? MUSB_POWER_HSENAB : 0; + musb_regs->power |= MUSB_POWER_SOFTCONN; } // Disconnect by disabling internal pull-up resistor on D+/D- void dcd_disconnect(uint8_t rhport) { - (void)rhport; - USB0->POWER &= ~USB_POWER_SOFTCONN; + musb_regs_t* musb_regs = MUSB_REGS(rhport); + musb_regs->power &= ~MUSB_POWER_SOFTCONN; } void dcd_sof_enable(uint8_t rhport, bool en) @@ -659,129 +654,119 @@ void dcd_sof_enable(uint8_t rhport, bool en) //--------------------------------------------------------------------+ // Endpoint API //--------------------------------------------------------------------+ +// static void edpt_setup(musb_regs_t* musb, uint8_t ep_addr, uint8_t ep_type, uint16_t ep_size){ +// const unsigned epn = tu_edpt_number(ep_addr); +// const unsigned dir_in = tu_edpt_dir(ep_addr); +// } // Configure endpoint's registers according to descriptor -bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc) -{ - (void) rhport; - +bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc) { const unsigned ep_addr = ep_desc->bEndpointAddress; const unsigned epn = tu_edpt_number(ep_addr); const unsigned dir_in = tu_edpt_dir(ep_addr); - const unsigned xfer = ep_desc->bmAttributes.xfer; const unsigned mps = tu_edpt_packet_size(ep_desc); - TU_ASSERT(epn < TUP_DCD_ENDPOINT_MAX); - pipe_state_t *pipe = &_dcd.pipe[dir_in][epn - 1]; pipe->buf = NULL; pipe->length = 0; pipe->remaining = 0; - volatile hw_endpoint_t *regs = edpt_regs(epn - 1); + musb_regs_t* musb = MUSB_REGS(rhport); + musb_ep_csr_t* ep_csr = get_ep_csr(musb, epn); + const uint8_t is_rx = 1 - dir_in; + musb_ep_maxp_csr_t* maxp_csr = &ep_csr->maxp_csr[is_rx]; + + maxp_csr->maxp = mps; + maxp_csr->csrh = 0; +#if MUSB_CFG_SHARED_FIFO if (dir_in) { - regs->TXMAXP = mps; - regs->TXCSRH = (xfer == TUSB_XFER_ISOCHRONOUS) ? USB_TXCSRH1_ISO : 0; - if (regs->TXCSRL & USB_TXCSRL1_TXRDY) - regs->TXCSRL = USB_TXCSRL1_CLRDT | USB_TXCSRL1_FLUSH; - else - regs->TXCSRL = USB_TXCSRL1_CLRDT; - USB0->TXIE |= TU_BIT(epn); - } else { - regs->RXMAXP = mps; - regs->RXCSRH = (xfer == TUSB_XFER_ISOCHRONOUS) ? USB_RXCSRH1_ISO : 0; - if (regs->RXCSRL & USB_RXCSRL1_RXRDY) - regs->RXCSRL = USB_RXCSRL1_CLRDT | USB_RXCSRL1_FLUSH; - else - regs->RXCSRL = USB_RXCSRL1_CLRDT; - USB0->RXIE |= TU_BIT(epn); + maxp_csr->csrh |= MUSB_CSRH_TX_MODE; } +#endif - /* Setup FIFO */ - int size_in_log2_minus3 = 28 - TU_MIN(28, __CLZ((uint32_t)mps)); - if ((8u << size_in_log2_minus3) < mps) ++size_in_log2_minus3; - unsigned addr = find_free_memory(size_in_log2_minus3); - TU_ASSERT(addr); + hwfifo_flush(musb, epn, is_rx, true); - USB0->EPIDX = epn; - if (dir_in) { - USB0->TXFIFOADD = addr; - USB0->TXFIFOSZ = size_in_log2_minus3; - } else { - USB0->RXFIFOADD = addr; - USB0->RXFIFOSZ = size_in_log2_minus3; - } + TU_ASSERT(hwfifo_config(musb, epn, is_rx, mps, false)); + musb->intren_ep[is_rx] |= TU_BIT(epn); return true; } -void dcd_edpt_close_all(uint8_t rhport) -{ - (void) rhport; - volatile hw_endpoint_t *regs = (volatile hw_endpoint_t *)(uintptr_t)&USB0->TXMAXP1; - unsigned const ie = NVIC_GetEnableIRQ(USB0_IRQn); - NVIC_DisableIRQ(USB0_IRQn); - USB0->TXIE = 1; /* Enable only EP0 */ - USB0->RXIE = 0; - for (unsigned i = 1; i < TUP_DCD_ENDPOINT_MAX; ++i) { - regs->TXMAXP = 0; - regs->TXCSRH = 0; - if (regs->TXCSRL & USB_TXCSRL1_TXRDY) - regs->TXCSRL = USB_TXCSRL1_CLRDT | USB_TXCSRL1_FLUSH; - else - regs->TXCSRL = USB_TXCSRL1_CLRDT; +bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { + const unsigned epn = tu_edpt_number(ep_addr); + const unsigned dir_in = tu_edpt_dir(ep_addr); + musb_regs_t* musb = MUSB_REGS(rhport); + musb_ep_csr_t* ep_csr = get_ep_csr(musb, epn); + const uint8_t is_rx = 1 - dir_in; + ep_csr->maxp_csr[is_rx].csrh = 0; + return hwfifo_config(musb, epn, is_rx, largest_packet_size, true); +} + +bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const *ep_desc ) { + const unsigned ep_addr = ep_desc->bEndpointAddress; + const unsigned epn = tu_edpt_number(ep_addr); + const unsigned dir_in = tu_edpt_dir(ep_addr); + const unsigned mps = tu_edpt_packet_size(ep_desc); + + unsigned const ie = musb_dcd_get_int_enable(rhport); + musb_dcd_int_disable(rhport); - regs->RXMAXP = 0; - regs->RXCSRH = 0; - if (regs->RXCSRL & USB_RXCSRL1_RXRDY) - regs->RXCSRL = USB_RXCSRL1_CLRDT | USB_RXCSRL1_FLUSH; - else - regs->RXCSRL = USB_RXCSRL1_CLRDT; + pipe_state_t *pipe = &_dcd.pipe[dir_in][epn - 1]; + pipe->buf = NULL; + pipe->length = 0; + pipe->remaining = 0; - USB0->EPIDX = i; - USB0->TXFIFOSZ = 0; - USB0->TXFIFOADD = 0; - USB0->RXFIFOSZ = 0; - USB0->RXFIFOADD = 0; + musb_regs_t* musb = MUSB_REGS(rhport); + musb_ep_csr_t* ep_csr = get_ep_csr(musb, epn); + const uint8_t is_rx = 1 - dir_in; + musb_ep_maxp_csr_t* maxp_csr = &ep_csr->maxp_csr[is_rx]; + + maxp_csr->maxp = mps; + maxp_csr->csrh |= MUSB_CSRH_ISO; +#if MUSB_CFG_SHARED_FIFO + if (dir_in) { + maxp_csr->csrh |= MUSB_CSRH_TX_MODE; } - if (ie) NVIC_EnableIRQ(USB0_IRQn); +#endif + + hwfifo_flush(musb, epn, is_rx, true); + +#if MUSB_CFG_DYNAMIC_FIFO + // fifo space is already allocated, keep the address and just change packet size + musb->fifo_size[is_rx] = hwfifo_byte2size(mps) | MUSB_FIFOSZ_DOUBLE_PACKET; +#endif + + musb->intren_ep[is_rx] |= TU_BIT(epn); + + if (ie) musb_dcd_int_enable(rhport); + + return true; } -void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) +void dcd_edpt_close_all(uint8_t rhport) { - (void)rhport; - unsigned const epn = tu_edpt_number(ep_addr); - unsigned const dir_in = tu_edpt_dir(ep_addr); + musb_regs_t* musb = MUSB_REGS(rhport); + unsigned const ie = musb_dcd_get_int_enable(rhport); + musb_dcd_int_disable(rhport); - hw_endpoint_t volatile *regs = edpt_regs(epn - 1); - unsigned const ie = NVIC_GetEnableIRQ(USB0_IRQn); - NVIC_DisableIRQ(USB0_IRQn); - if (dir_in) { - USB0->TXIE &= ~TU_BIT(epn); - regs->TXMAXP = 0; - regs->TXCSRH = 0; - if (regs->TXCSRL & USB_TXCSRL1_TXRDY) - regs->TXCSRL = USB_TXCSRL1_CLRDT | USB_TXCSRL1_FLUSH; - else - regs->TXCSRL = USB_TXCSRL1_CLRDT; + musb->intr_txen = 1; /* Enable only EP0 */ + musb->intr_rxen = 0; + for (unsigned i = 1; i < TUP_DCD_ENDPOINT_MAX; ++i) { + musb_ep_csr_t* ep_csr = get_ep_csr(musb, i); + for (unsigned d = 0; d < 2; d++) { + musb_ep_maxp_csr_t* maxp_csr = &ep_csr->maxp_csr[d]; + hwfifo_flush(musb, i, d, true); + hwfifo_reset(musb, i, d); + maxp_csr->maxp = 0; + maxp_csr->csrh = 0; + } + } - USB0->EPIDX = epn; - USB0->TXFIFOSZ = 0; - USB0->TXFIFOADD = 0; - } else { - USB0->RXIE &= ~TU_BIT(epn); - regs->RXMAXP = 0; - regs->RXCSRH = 0; - if (regs->RXCSRL & USB_RXCSRL1_RXRDY) - regs->RXCSRL = USB_RXCSRL1_CLRDT | USB_RXCSRL1_FLUSH; - else - regs->RXCSRL = USB_RXCSRL1_CLRDT; +#if MUSB_CFG_DYNAMIC_FIFO + alloced_fifo_bytes = CFG_TUD_ENDPOINT0_SIZE; +#endif - USB0->EPIDX = epn; - USB0->RXFIFOSZ = 0; - USB0->RXFIFOADD = 0; - } - if (ie) NVIC_EnableIRQ(USB0_IRQn); + if (ie) musb_dcd_int_enable(rhport); } // Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack @@ -791,18 +776,22 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t t bool ret; // TU_LOG1("X %x %d\r\n", ep_addr, total_bytes); unsigned const epnum = tu_edpt_number(ep_addr); - unsigned const ie = NVIC_GetEnableIRQ(USB0_IRQn); - NVIC_DisableIRQ(USB0_IRQn); + unsigned const ie = musb_dcd_get_int_enable(rhport); + musb_dcd_int_disable(rhport); + if (epnum) { _dcd.pipe_buf_is_fifo[tu_edpt_dir(ep_addr)] &= ~TU_BIT(epnum - 1); ret = edpt_n_xfer(rhport, ep_addr, buffer, total_bytes); - } else + } else { ret = edpt0_xfer(rhport, ep_addr, buffer, total_bytes); - if (ie) NVIC_EnableIRQ(USB0_IRQn); + } + + if (ie) musb_dcd_int_enable(rhport); return ret; } -// Submit a transfer where is managed by FIFO, When complete dcd_event_xfer_complete() is invoked to notify the stack - optional, however, must be listed in usbd.c +// Submit a transfer where is managed by FIFO, When complete dcd_event_xfer_complete() is invoked to notify the stack +// - optional, however, must be listed in usbd.c bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) { (void)rhport; @@ -810,99 +799,104 @@ bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_ // TU_LOG1("X %x %d\r\n", ep_addr, total_bytes); unsigned const epnum = tu_edpt_number(ep_addr); TU_ASSERT(epnum); - unsigned const ie = NVIC_GetEnableIRQ(USB0_IRQn); - NVIC_DisableIRQ(USB0_IRQn); + unsigned const ie = musb_dcd_get_int_enable(rhport); + musb_dcd_int_disable(rhport); _dcd.pipe_buf_is_fifo[tu_edpt_dir(ep_addr)] |= TU_BIT(epnum - 1); ret = edpt_n_xfer(rhport, ep_addr, (uint8_t*)ff, total_bytes); - if (ie) NVIC_EnableIRQ(USB0_IRQn); + if (ie) musb_dcd_int_enable(rhport); return ret; } // Stall endpoint -void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) -{ - (void)rhport; +void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { + unsigned const ie = musb_dcd_get_int_enable(rhport); + musb_dcd_int_disable(rhport); + unsigned const epn = tu_edpt_number(ep_addr); - unsigned const ie = NVIC_GetEnableIRQ(USB0_IRQn); - NVIC_DisableIRQ(USB0_IRQn); + musb_regs_t* musb_regs = MUSB_REGS(rhport); + musb_ep_csr_t* ep_csr = get_ep_csr(musb_regs, epn); + if (0 == epn) { if (!ep_addr) { /* Ignore EP80 */ _dcd.setup_packet.bmRequestType = REQUEST_TYPE_INVALID; _dcd.pipe0.buf = NULL; - USB0->CSRL0 = USB_CSRL0_STALL; + ep_csr->csr0l = MUSB_CSRL0_STALL; } } else { - volatile hw_endpoint_t *regs = edpt_regs(epn - 1); - if (tu_edpt_dir(ep_addr)) { /* IN */ - regs->TXCSRL = USB_TXCSRL1_STALL; - } else { /* OUT */ - TU_ASSERT(!(regs->RXCSRL & USB_RXCSRL1_RXRDY),); - regs->RXCSRL = USB_RXCSRL1_STALL; - } + const uint8_t is_rx = 1 - tu_edpt_dir(ep_addr); + ep_csr->maxp_csr[is_rx].csrl = MUSB_CSRL_SEND_STALL(is_rx); } - if (ie) NVIC_EnableIRQ(USB0_IRQn); + + if (ie) musb_dcd_int_enable(rhport); } // clear stall, data toggle is also reset to DATA0 void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { (void)rhport; + unsigned const ie = musb_dcd_get_int_enable(rhport); + musb_dcd_int_disable(rhport); + unsigned const epn = tu_edpt_number(ep_addr); - hw_endpoint_t volatile *regs = edpt_regs(epn - 1); - unsigned const ie = NVIC_GetEnableIRQ(USB0_IRQn); - NVIC_DisableIRQ(USB0_IRQn); - if (tu_edpt_dir(ep_addr)) { /* IN */ - regs->TXCSRL = USB_TXCSRL1_CLRDT; - } else { /* OUT */ - regs->RXCSRL = USB_RXCSRL1_CLRDT; - } - if (ie) NVIC_EnableIRQ(USB0_IRQn); + musb_regs_t* musb_regs = MUSB_REGS(rhport); + musb_ep_csr_t* ep_csr = get_ep_csr(musb_regs, epn); + const uint8_t is_rx = 1 - tu_edpt_dir(ep_addr); + + ep_csr->maxp_csr[is_rx].csrl = MUSB_CSRL_CLEAR_DATA_TOGGLE(is_rx); + + if (ie) musb_dcd_int_enable(rhport); } /*------------------------------------------------------------------- * ISR *-------------------------------------------------------------------*/ -void dcd_int_handler(uint8_t rhport) -{ - uint_fast8_t is, txis, rxis; +void dcd_int_handler(uint8_t rhport) { + musb_regs_t* musb_regs = MUSB_REGS(rhport); + const uint8_t saved_index = musb_regs->index; // save endpoint index + + //Part specific ISR setup/entry + musb_dcd_int_handler_enter(rhport); - is = USB0->IS; /* read and clear interrupt status */ - txis = USB0->TXIS; /* read and clear interrupt status */ - rxis = USB0->RXIS; /* read and clear interrupt status */ + uint_fast8_t intr_usb = musb_regs->intr_usb; // a read will clear this interrupt status + uint_fast8_t intr_tx = musb_regs->intr_tx; // a read will clear this interrupt status + uint_fast8_t intr_rx = musb_regs->intr_rx; // a read will clear this interrupt status // TU_LOG1("D%2x T%2x R%2x\r\n", is, txis, rxis); - is &= USB0->IE; /* Clear disabled interrupts */ - if (is & USB_IS_DISCON) { + intr_usb &= musb_regs->intr_usben; /* Clear disabled interrupts */ + if (intr_usb & MUSB_IS_DISCON) { } - if (is & USB_IS_SOF) { + if (intr_usb & MUSB_IS_SOF) { dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true); } - if (is & USB_IS_RESET) { + if (intr_usb & MUSB_IS_RESET) { process_bus_reset(rhport); } - if (is & USB_IS_RESUME) { + if (intr_usb & MUSB_IS_RESUME) { dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true); } - if (is & USB_IS_SUSPEND) { + if (intr_usb & MUSB_IS_SUSPEND) { dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true); } - txis &= USB0->TXIE; /* Clear disabled interrupts */ - if (txis & USB_TXIE_EP0) { + intr_tx &= musb_regs->intr_txen; /* Clear disabled interrupts */ + if (intr_tx & TU_BIT(0)) { process_ep0(rhport); - txis &= ~TU_BIT(0); + intr_tx &= ~TU_BIT(0); } - while (txis) { - unsigned const num = __builtin_ctz(txis); + while (intr_tx) { + unsigned const num = __builtin_ctz(intr_tx); process_edpt_n(rhport, tu_edpt_addr(num, TUSB_DIR_IN)); - txis &= ~TU_BIT(num); + intr_tx &= ~TU_BIT(num); } - rxis &= USB0->RXIE; /* Clear disabled interrupts */ - while (rxis) { - unsigned const num = __builtin_ctz(rxis); + + intr_rx &= musb_regs->intr_rxen; /* Clear disabled interrupts */ + while (intr_rx) { + unsigned const num = __builtin_ctz(intr_rx); process_edpt_n(rhport, tu_edpt_addr(num, TUSB_DIR_OUT)); - rxis &= ~TU_BIT(num); + intr_rx &= ~TU_BIT(num); } + + musb_regs->index = saved_index; // restore endpoint index } #endif diff --git a/src/portable/mentor/musb/hcd_musb.c b/src/portable/mentor/musb/hcd_musb.c index 5312c2812..8fc225676 100644 --- a/src/portable/mentor/musb/hcd_musb.c +++ b/src/portable/mentor/musb/hcd_musb.c @@ -37,16 +37,10 @@ _Pragma("GCC diagnostic ignored \"-Waddress-of-packed-member\""); #include "host/hcd.h" -#if TU_CHECK_MCU(OPT_MCU_MSP432E4) - #include "musb_msp432e.h" - -#elif TU_CHECK_MCU(OPT_MCU_TM4C123, OPT_MCU_TM4C129) - #include "musb_tm4c.h" - - // HACK generalize later - #include "musb_type.h" - #define FIFO0_WORD FIFO0 +#include "musb_type.h" +#if TU_CHECK_MCU(OPT_MCU_MSP432E4, OPT_MCU_TM4C123, OPT_MCU_TM4C129) + #include "musb_ti.h" #else #error "Unsupported MCUs" #endif diff --git a/src/portable/mentor/musb/musb_max32.h b/src/portable/mentor/musb/musb_max32.h new file mode 100644 index 000000000..35849b5f8 --- /dev/null +++ b/src/portable/mentor/musb/musb_max32.h @@ -0,0 +1,150 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024, Brent Kowal (Analog Devices, Inc) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef TUSB_MUSB_MAX32_H_ +#define TUSB_MUSB_MAX32_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "mxc_device.h" +#include "usbhs_regs.h" + +#define MUSB_CFG_SHARED_FIFO 1 // shared FIFO for TX and RX endpoints +#define MUSB_CFG_DYNAMIC_FIFO 0 // dynamic EP FIFO sizing + +const uintptr_t MUSB_BASES[] = { MXC_BASE_USBHS }; + +#if CFG_TUD_ENABLED +#define USBHS_M31_CLOCK_RECOVERY + +// Mapping of IRQ numbers to port. Currently just 1. +static const IRQn_Type musb_irqs[] = { + USB_IRQn +}; + +TU_ATTR_ALWAYS_INLINE static inline void musb_dcd_int_enable(uint8_t rhport) { + NVIC_EnableIRQ(musb_irqs[rhport]); +} + +TU_ATTR_ALWAYS_INLINE static inline void musb_dcd_int_disable(uint8_t rhport) { + NVIC_DisableIRQ(musb_irqs[rhport]); +} + +TU_ATTR_ALWAYS_INLINE static inline unsigned musb_dcd_get_int_enable(uint8_t rhport) { + #ifdef NVIC_GetEnableIRQ // only defined in CMSIS 5 + return NVIC_GetEnableIRQ(musb_irqs[rhport]); + #else + uint32_t IRQn = (uint32_t) musb_irqs[rhport]; + return ((NVIC->ISER[IRQn >> 5UL] & (1UL << (IRQn & 0x1FUL))) != 0UL) ? 1UL : 0UL; + #endif +} + +TU_ATTR_ALWAYS_INLINE static inline void musb_dcd_int_clear(uint8_t rhport) { + NVIC_ClearPendingIRQ(musb_irqs[rhport]); +} + +static inline void musb_dcd_int_handler_enter(uint8_t rhport) { + mxc_usbhs_regs_t* hs_phy = MXC_USBHS; + uint32_t mxm_int, mxm_int_en, mxm_is; + + //Handle PHY specific events + mxm_int = hs_phy->mxm_int; + mxm_int_en = hs_phy->mxm_int_en; + mxm_is = mxm_int & mxm_int_en; + hs_phy->mxm_int = mxm_is; + + if (mxm_is & MXC_F_USBHS_MXM_INT_NOVBUS) { + dcd_event_bus_signal(rhport, DCD_EVENT_UNPLUGGED, true); + } +} + +static inline void musb_dcd_phy_init(uint8_t rhport) { + (void) rhport; + mxc_usbhs_regs_t* hs_phy = MXC_USBHS; + + // Interrupt for VBUS disconnect + hs_phy->mxm_int_en |= MXC_F_USBHS_MXM_INT_EN_NOVBUS; + + musb_dcd_int_clear(rhport); + + // Unsuspend the MAC + hs_phy->mxm_suspend = 0; + + // Configure PHY + hs_phy->m31_phy_xcfgi_31_0 = (0x1 << 3) | (0x1 << 11); + hs_phy->m31_phy_xcfgi_63_32 = 0; + hs_phy->m31_phy_xcfgi_95_64 = 0x1 << (72 - 64); + hs_phy->m31_phy_xcfgi_127_96 = 0; + + #ifdef USBHS_M31_CLOCK_RECOVERY + hs_phy->m31_phy_noncry_rstb = 1; + hs_phy->m31_phy_noncry_en = 1; + hs_phy->m31_phy_outclksel = 0; + hs_phy->m31_phy_coreclkin = 0; + hs_phy->m31_phy_xtlsel = 2; /* Select 25 MHz clock */ + #else + hs_phy->m31_phy_noncry_rstb = 0; + hs_phy->m31_phy_noncry_en = 0; + hs_phy->m31_phy_outclksel = 1; + hs_phy->m31_phy_coreclkin = 1; + hs_phy->m31_phy_xtlsel = 3; /* Select 30 MHz clock */ + #endif + hs_phy->m31_phy_pll_en = 1; + hs_phy->m31_phy_oscouten = 1; + + /* Reset PHY */ + hs_phy->m31_phy_ponrst = 0; + hs_phy->m31_phy_ponrst = 1; +} + +// static inline void musb_dcd_setup_fifo(uint8_t rhport, unsigned epnum, unsigned dir_in, unsigned mps) { +// (void) mps; +// +// //Most likely the caller has already grabbed the right register block. But +// //as a precaution save and restore the register bank anyways +// unsigned saved_index = musb_periph_inst[rhport]->index; +// +// musb_periph_inst[rhport]->index = epnum; +// +// //Disable double buffering +// if (dir_in) { +// musb_periph_inst[rhport]->incsru |= (MXC_F_USBHS_INCSRU_DPKTBUFDIS | MXC_F_USBHS_INCSRU_MODE); +// } else { +// musb_periph_inst[rhport]->outcsru |= (MXC_F_USBHS_OUTCSRU_DPKTBUFDIS); +// } +// +// musb_periph_inst[rhport]->index = saved_index; +// } + +#endif // CFG_TUD_ENABLED + +#ifdef __cplusplus +} +#endif + +#endif // TUSB_MUSB_MAX32_H_ diff --git a/src/portable/mentor/musb/musb_msp432e.h b/src/portable/mentor/musb/musb_msp432e.h deleted file mode 100644 index fce21de88..000000000 --- a/src/portable/mentor/musb/musb_msp432e.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2021, Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#ifndef _TUSB_MUSB_MSP432E_H_ -#define _TUSB_MUSB_MSP432E_H_ - -#ifdef __cplusplus - extern "C" { -#endif - -#include "msp.h" - -#ifdef __cplusplus - } -#endif - -#endif diff --git a/src/portable/mentor/musb/musb_tm4c.h b/src/portable/mentor/musb/musb_ti.h index 65a1751b0..d17e836ee 100644 --- a/src/portable/mentor/musb/musb_tm4c.h +++ b/src/portable/mentor/musb/musb_ti.h @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2021, Ha Thach (tinyusb.org) + * Copyright (c) 2024, Brent Kowal (Analog Devices, Inc) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,8 +24,8 @@ * This file is part of the TinyUSB stack. */ -#ifndef _TUSB_MUSB_TM4C_H_ -#define _TUSB_MUSB_TM4C_H_ +#ifndef TUSB_MUSB_TI_H_ +#define TUSB_MUSB_TI_H_ #ifdef __cplusplus extern "C" { @@ -33,13 +33,59 @@ #if CFG_TUSB_MCU == OPT_MCU_TM4C123 #include "TM4C123.h" + #define FIFO0_WORD FIFO0 + #define FIFO1_WORD FIFO1 //#elif CFG_TUSB_MCU == OPT_MCU_TM4C129 +#elif CFG_TUSB_MCU == OPT_MCU_MSP432E4 + #include "msp.h" #else #error "Unsupported MCUs" #endif +#define MUSB_CFG_SHARED_FIFO 0 +#define MUSB_CFG_DYNAMIC_FIFO 1 +#define MUSB_CFG_DYNAMIC_FIFO_SIZE 4096 + +const uintptr_t MUSB_BASES[] = { USB0_BASE }; + +// Header supports both device and host modes. Only include what's necessary +#if CFG_TUD_ENABLED + +// Mapping of IRQ numbers to port. Currently just 1. +static const IRQn_Type musb_irqs[] = { + USB0_IRQn +}; + +static inline void musb_dcd_phy_init(uint8_t rhport){ + (void)rhport; + //Nothing to do for this part +} + +TU_ATTR_ALWAYS_INLINE static inline void musb_dcd_int_enable(uint8_t rhport) { + NVIC_EnableIRQ(musb_irqs[rhport]); +} + +TU_ATTR_ALWAYS_INLINE static inline void musb_dcd_int_disable(uint8_t rhport) { + NVIC_DisableIRQ(musb_irqs[rhport]); +} + +TU_ATTR_ALWAYS_INLINE static inline unsigned musb_dcd_get_int_enable(uint8_t rhport) { + return NVIC_GetEnableIRQ(musb_irqs[rhport]); +} + +TU_ATTR_ALWAYS_INLINE static inline void musb_dcd_int_clear(uint8_t rhport) { + NVIC_ClearPendingIRQ(musb_irqs[rhport]); +} + +static inline void musb_dcd_int_handler_enter(uint8_t rhport) { + (void)rhport; + //Nothing to do for this part +} + +#endif // CFG_TUD_ENABLED + #ifdef __cplusplus } #endif -#endif +#endif // TUSB_MUSB_TI_H_ diff --git a/src/portable/mentor/musb/musb_type.h b/src/portable/mentor/musb/musb_type.h index 8f83305a5..4e448c0ed 100644 --- a/src/portable/mentor/musb/musb_type.h +++ b/src/portable/mentor/musb/musb_type.h @@ -1,3 +1,29 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + /****************************************************************************** * * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ @@ -32,2590 +58,696 @@ * *******************************************************************************/ -#ifndef _TUSB_MUSB_TYPE_H_ -#define _TUSB_MUSB_TYPE_H_ +#ifndef TUSB_MUSB_TYPE_H_ +#define TUSB_MUSB_TYPE_H_ + +#include "stdint.h" #ifdef __cplusplus extern "C" { #endif -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_FADDR register. -// -//***************************************************************************** -#define USB_FADDR_M 0x0000007F // Function Address -#define USB_FADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_POWER register. -// -//***************************************************************************** -#define USB_POWER_ISOUP 0x00000080 // Isochronous Update -#define USB_POWER_SOFTCONN 0x00000040 // Soft Connect/Disconnect -#define USB_POWER_HSENAB 0x00000020 // High Speed Enable -#define USB_POWER_HSMODE 0x00000010 // High Speed Enable -#define USB_POWER_RESET 0x00000008 // RESET Signaling -#define USB_POWER_RESUME 0x00000004 // RESUME Signaling -#define USB_POWER_SUSPEND 0x00000002 // SUSPEND Mode -#define USB_POWER_PWRDNPHY 0x00000001 // Power Down PHY - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXIS register. -// -//***************************************************************************** -#define USB_TXIS_EP7 0x00000080 // TX Endpoint 7 Interrupt -#define USB_TXIS_EP6 0x00000040 // TX Endpoint 6 Interrupt -#define USB_TXIS_EP5 0x00000020 // TX Endpoint 5 Interrupt -#define USB_TXIS_EP4 0x00000010 // TX Endpoint 4 Interrupt -#define USB_TXIS_EP3 0x00000008 // TX Endpoint 3 Interrupt -#define USB_TXIS_EP2 0x00000004 // TX Endpoint 2 Interrupt -#define USB_TXIS_EP1 0x00000002 // TX Endpoint 1 Interrupt -#define USB_TXIS_EP0 0x00000001 // TX and RX Endpoint 0 Interrupt - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXIS register. -// -//***************************************************************************** -#define USB_RXIS_EP7 0x00000080 // RX Endpoint 7 Interrupt -#define USB_RXIS_EP6 0x00000040 // RX Endpoint 6 Interrupt -#define USB_RXIS_EP5 0x00000020 // RX Endpoint 5 Interrupt -#define USB_RXIS_EP4 0x00000010 // RX Endpoint 4 Interrupt -#define USB_RXIS_EP3 0x00000008 // RX Endpoint 3 Interrupt -#define USB_RXIS_EP2 0x00000004 // RX Endpoint 2 Interrupt -#define USB_RXIS_EP1 0x00000002 // RX Endpoint 1 Interrupt - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXIE register. -// -//***************************************************************************** -#define USB_TXIE_EP7 0x00000080 // TX Endpoint 7 Interrupt Enable -#define USB_TXIE_EP6 0x00000040 // TX Endpoint 6 Interrupt Enable -#define USB_TXIE_EP5 0x00000020 // TX Endpoint 5 Interrupt Enable -#define USB_TXIE_EP4 0x00000010 // TX Endpoint 4 Interrupt Enable -#define USB_TXIE_EP3 0x00000008 // TX Endpoint 3 Interrupt Enable -#define USB_TXIE_EP2 0x00000004 // TX Endpoint 2 Interrupt Enable -#define USB_TXIE_EP1 0x00000002 // TX Endpoint 1 Interrupt Enable -#define USB_TXIE_EP0 0x00000001 // TX and RX Endpoint 0 Interrupt - // Enable - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXIE register. -// -//***************************************************************************** -#define USB_RXIE_EP7 0x00000080 // RX Endpoint 7 Interrupt Enable -#define USB_RXIE_EP6 0x00000040 // RX Endpoint 6 Interrupt Enable -#define USB_RXIE_EP5 0x00000020 // RX Endpoint 5 Interrupt Enable -#define USB_RXIE_EP4 0x00000010 // RX Endpoint 4 Interrupt Enable -#define USB_RXIE_EP3 0x00000008 // RX Endpoint 3 Interrupt Enable -#define USB_RXIE_EP2 0x00000004 // RX Endpoint 2 Interrupt Enable -#define USB_RXIE_EP1 0x00000002 // RX Endpoint 1 Interrupt Enable - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_IS register. -// -//***************************************************************************** -#define USB_IS_VBUSERR 0x00000080 // VBUS Error (OTG only) -#define USB_IS_SESREQ 0x00000040 // SESSION REQUEST (OTG only) -#define USB_IS_DISCON 0x00000020 // Session Disconnect (OTG only) -#define USB_IS_CONN 0x00000010 // Session Connect -#define USB_IS_SOF 0x00000008 // Start of Frame -#define USB_IS_BABBLE 0x00000004 // Babble Detected -#define USB_IS_RESET 0x00000004 // RESET Signaling Detected -#define USB_IS_RESUME 0x00000002 // RESUME Signaling Detected -#define USB_IS_SUSPEND 0x00000001 // SUSPEND Signaling Detected - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_IE register. -// -//***************************************************************************** -#define USB_IE_VBUSERR 0x00000080 // Enable VBUS Error Interrupt (OTG - // only) -#define USB_IE_SESREQ 0x00000040 // Enable Session Request (OTG - // only) -#define USB_IE_DISCON 0x00000020 // Enable Disconnect Interrupt -#define USB_IE_CONN 0x00000010 // Enable Connect Interrupt -#define USB_IE_SOF 0x00000008 // Enable Start-of-Frame Interrupt -#define USB_IE_BABBLE 0x00000004 // Enable Babble Interrupt -#define USB_IE_RESET 0x00000004 // Enable RESET Interrupt -#define USB_IE_RESUME 0x00000002 // Enable RESUME Interrupt -#define USB_IE_SUSPND 0x00000001 // Enable SUSPEND Interrupt - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_FRAME register. -// -//***************************************************************************** -#define USB_FRAME_M 0x000007FF // Frame Number -#define USB_FRAME_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_EPIDX register. -// -//***************************************************************************** -#define USB_EPIDX_EPIDX_M 0x0000000F // Endpoint Index -#define USB_EPIDX_EPIDX_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TEST register. -// -//***************************************************************************** -#define USB_TEST_FORCEH 0x00000080 // Force Host Mode -#define USB_TEST_FIFOACC 0x00000040 // FIFO Access -#define USB_TEST_FORCEFS 0x00000020 // Force Full-Speed Mode -#define USB_TEST_FORCEHS 0x00000010 // Force High-Speed Mode -#define USB_TEST_TESTPKT 0x00000008 // Test Packet Mode Enable -#define USB_TEST_TESTK 0x00000004 // Test_K Mode Enable -#define USB_TEST_TESTJ 0x00000002 // Test_J Mode Enable -#define USB_TEST_TESTSE0NAK 0x00000001 // Test_SE0_NAK Test Mode Enable - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_FIFO0 register. -// -//***************************************************************************** -#define USB_FIFO0_EPDATA_M 0xFFFFFFFF // Endpoint Data -#define USB_FIFO0_EPDATA_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_FIFO1 register. -// -//***************************************************************************** -#define USB_FIFO1_EPDATA_M 0xFFFFFFFF // Endpoint Data -#define USB_FIFO1_EPDATA_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_FIFO2 register. -// -//***************************************************************************** -#define USB_FIFO2_EPDATA_M 0xFFFFFFFF // Endpoint Data -#define USB_FIFO2_EPDATA_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_FIFO3 register. -// -//***************************************************************************** -#define USB_FIFO3_EPDATA_M 0xFFFFFFFF // Endpoint Data -#define USB_FIFO3_EPDATA_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_FIFO4 register. -// -//***************************************************************************** -#define USB_FIFO4_EPDATA_M 0xFFFFFFFF // Endpoint Data -#define USB_FIFO4_EPDATA_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_FIFO5 register. -// -//***************************************************************************** -#define USB_FIFO5_EPDATA_M 0xFFFFFFFF // Endpoint Data -#define USB_FIFO5_EPDATA_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_FIFO6 register. -// -//***************************************************************************** -#define USB_FIFO6_EPDATA_M 0xFFFFFFFF // Endpoint Data -#define USB_FIFO6_EPDATA_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_FIFO7 register. -// -//***************************************************************************** -#define USB_FIFO7_EPDATA_M 0xFFFFFFFF // Endpoint Data -#define USB_FIFO7_EPDATA_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_DEVCTL register. -// -//***************************************************************************** -#define USB_DEVCTL_DEV 0x00000080 // Device Mode (OTG only) -#define USB_DEVCTL_FSDEV 0x00000040 // Full-Speed Device Detected -#define USB_DEVCTL_LSDEV 0x00000020 // Low-Speed Device Detected -#define USB_DEVCTL_VBUS_M 0x00000018 // VBUS Level (OTG only) -#define USB_DEVCTL_VBUS_NONE 0x00000000 // Below SessionEnd -#define USB_DEVCTL_VBUS_SEND 0x00000008 // Above SessionEnd, below AValid -#define USB_DEVCTL_VBUS_AVALID 0x00000010 // Above AValid, below VBUSValid -#define USB_DEVCTL_VBUS_VALID 0x00000018 // Above VBUSValid -#define USB_DEVCTL_HOST 0x00000004 // Host Mode -#define USB_DEVCTL_HOSTREQ 0x00000002 // Host Request (OTG only) -#define USB_DEVCTL_SESSION 0x00000001 // Session Start/End (OTG only) - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_CCONF register. -// -//***************************************************************************** -#define USB_CCONF_TXEDMA 0x00000002 // TX Early DMA Enable -#define USB_CCONF_RXEDMA 0x00000001 // TX Early DMA Enable - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXFIFOSZ register. -// -//***************************************************************************** -#define USB_TXFIFOSZ_DPB 0x00000010 // Double Packet Buffer Support -#define USB_TXFIFOSZ_SIZE_M 0x0000000F // Max Packet Size -#define USB_TXFIFOSZ_SIZE_8 0x00000000 // 8 -#define USB_TXFIFOSZ_SIZE_16 0x00000001 // 16 -#define USB_TXFIFOSZ_SIZE_32 0x00000002 // 32 -#define USB_TXFIFOSZ_SIZE_64 0x00000003 // 64 -#define USB_TXFIFOSZ_SIZE_128 0x00000004 // 128 -#define USB_TXFIFOSZ_SIZE_256 0x00000005 // 256 -#define USB_TXFIFOSZ_SIZE_512 0x00000006 // 512 -#define USB_TXFIFOSZ_SIZE_1024 0x00000007 // 1024 -#define USB_TXFIFOSZ_SIZE_2048 0x00000008 // 2048 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXFIFOSZ register. -// -//***************************************************************************** -#define USB_RXFIFOSZ_DPB 0x00000010 // Double Packet Buffer Support -#define USB_RXFIFOSZ_SIZE_M 0x0000000F // Max Packet Size -#define USB_RXFIFOSZ_SIZE_8 0x00000000 // 8 -#define USB_RXFIFOSZ_SIZE_16 0x00000001 // 16 -#define USB_RXFIFOSZ_SIZE_32 0x00000002 // 32 -#define USB_RXFIFOSZ_SIZE_64 0x00000003 // 64 -#define USB_RXFIFOSZ_SIZE_128 0x00000004 // 128 -#define USB_RXFIFOSZ_SIZE_256 0x00000005 // 256 -#define USB_RXFIFOSZ_SIZE_512 0x00000006 // 512 -#define USB_RXFIFOSZ_SIZE_1024 0x00000007 // 1024 -#define USB_RXFIFOSZ_SIZE_2048 0x00000008 // 2048 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXFIFOADD -// register. -// -//***************************************************************************** -#define USB_TXFIFOADD_ADDR_M 0x000001FF // Transmit/Receive Start Address -#define USB_TXFIFOADD_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXFIFOADD -// register. -// -//***************************************************************************** -#define USB_RXFIFOADD_ADDR_M 0x000001FF // Transmit/Receive Start Address -#define USB_RXFIFOADD_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_ULPIVBUSCTL -// register. -// -//***************************************************************************** -#define USB_ULPIVBUSCTL_USEEXTVBUSIND \ - 0x00000002 // Use External VBUS Indicator -#define USB_ULPIVBUSCTL_USEEXTVBUS \ - 0x00000001 // Use External VBUS - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_ULPIREGDATA -// register. -// -//***************************************************************************** -#define USB_ULPIREGDATA_REGDATA_M \ - 0x000000FF // Register Data -#define USB_ULPIREGDATA_REGDATA_S \ - 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_ULPIREGADDR -// register. -// -//***************************************************************************** -#define USB_ULPIREGADDR_ADDR_M 0x000000FF // Register Address -#define USB_ULPIREGADDR_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_ULPIREGCTL -// register. -// -//***************************************************************************** -#define USB_ULPIREGCTL_RDWR 0x00000004 // Read/Write Control -#define USB_ULPIREGCTL_REGCMPLT 0x00000002 // Register Access Complete -#define USB_ULPIREGCTL_REGACC 0x00000001 // Initiate Register Access - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_EPINFO register. -// -//***************************************************************************** -#define USB_EPINFO_RXEP_M 0x000000F0 // RX Endpoints -#define USB_EPINFO_TXEP_M 0x0000000F // TX Endpoints -#define USB_EPINFO_RXEP_S 4 -#define USB_EPINFO_TXEP_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RAMINFO register. -// -//***************************************************************************** -#define USB_RAMINFO_DMACHAN_M 0x000000F0 // DMA Channels -#define USB_RAMINFO_RAMBITS_M 0x0000000F // RAM Address Bus Width -#define USB_RAMINFO_DMACHAN_S 4 -#define USB_RAMINFO_RAMBITS_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_CONTIM register. -// -//***************************************************************************** -#define USB_CONTIM_WTCON_M 0x000000F0 // Connect Wait -#define USB_CONTIM_WTID_M 0x0000000F // Wait ID -#define USB_CONTIM_WTCON_S 4 -#define USB_CONTIM_WTID_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_VPLEN register. -// -//***************************************************************************** -#define USB_VPLEN_VPLEN_M 0x000000FF // VBUS Pulse Length -#define USB_VPLEN_VPLEN_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_HSEOF register. -// -//***************************************************************************** -#define USB_HSEOF_HSEOFG_M 0x000000FF // HIgh-Speed End-of-Frame Gap -#define USB_HSEOF_HSEOFG_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_FSEOF register. -// -//***************************************************************************** -#define USB_FSEOF_FSEOFG_M 0x000000FF // Full-Speed End-of-Frame Gap -#define USB_FSEOF_FSEOFG_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_LSEOF register. -// -//***************************************************************************** -#define USB_LSEOF_LSEOFG_M 0x000000FF // Low-Speed End-of-Frame Gap -#define USB_LSEOF_LSEOFG_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXFUNCADDR0 -// register. -// -//***************************************************************************** -#define USB_TXFUNCADDR0_ADDR_M 0x0000007F // Device Address -#define USB_TXFUNCADDR0_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXHUBADDR0 -// register. -// -//***************************************************************************** -#define USB_TXHUBADDR0_ADDR_M 0x0000007F // Hub Address -#define USB_TXHUBADDR0_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXHUBPORT0 -// register. -// -//***************************************************************************** -#define USB_TXHUBPORT0_PORT_M 0x0000007F // Hub Port -#define USB_TXHUBPORT0_PORT_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXFUNCADDR1 -// register. -// -//***************************************************************************** -#define USB_TXFUNCADDR1_ADDR_M 0x0000007F // Device Address -#define USB_TXFUNCADDR1_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXHUBADDR1 -// register. -// -//***************************************************************************** -#define USB_TXHUBADDR1_ADDR_M 0x0000007F // Hub Address -#define USB_TXHUBADDR1_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXHUBPORT1 -// register. -// -//***************************************************************************** -#define USB_TXHUBPORT1_PORT_M 0x0000007F // Hub Port -#define USB_TXHUBPORT1_PORT_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXFUNCADDR1 -// register. -// -//***************************************************************************** -#define USB_RXFUNCADDR1_ADDR_M 0x0000007F // Device Address -#define USB_RXFUNCADDR1_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXHUBADDR1 -// register. -// -//***************************************************************************** -#define USB_RXHUBADDR1_ADDR_M 0x0000007F // Hub Address -#define USB_RXHUBADDR1_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXHUBPORT1 -// register. -// -//***************************************************************************** -#define USB_RXHUBPORT1_PORT_M 0x0000007F // Hub Port -#define USB_RXHUBPORT1_PORT_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXFUNCADDR2 -// register. -// -//***************************************************************************** -#define USB_TXFUNCADDR2_ADDR_M 0x0000007F // Device Address -#define USB_TXFUNCADDR2_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXHUBADDR2 -// register. -// -//***************************************************************************** -#define USB_TXHUBADDR2_ADDR_M 0x0000007F // Hub Address -#define USB_TXHUBADDR2_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXHUBPORT2 -// register. -// -//***************************************************************************** -#define USB_TXHUBPORT2_PORT_M 0x0000007F // Hub Port -#define USB_TXHUBPORT2_PORT_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXFUNCADDR2 -// register. -// -//***************************************************************************** -#define USB_RXFUNCADDR2_ADDR_M 0x0000007F // Device Address -#define USB_RXFUNCADDR2_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXHUBADDR2 -// register. -// -//***************************************************************************** -#define USB_RXHUBADDR2_ADDR_M 0x0000007F // Hub Address -#define USB_RXHUBADDR2_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXHUBPORT2 -// register. -// -//***************************************************************************** -#define USB_RXHUBPORT2_PORT_M 0x0000007F // Hub Port -#define USB_RXHUBPORT2_PORT_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXFUNCADDR3 -// register. -// -//***************************************************************************** -#define USB_TXFUNCADDR3_ADDR_M 0x0000007F // Device Address -#define USB_TXFUNCADDR3_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXHUBADDR3 -// register. -// -//***************************************************************************** -#define USB_TXHUBADDR3_ADDR_M 0x0000007F // Hub Address -#define USB_TXHUBADDR3_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXHUBPORT3 -// register. -// -//***************************************************************************** -#define USB_TXHUBPORT3_PORT_M 0x0000007F // Hub Port -#define USB_TXHUBPORT3_PORT_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXFUNCADDR3 -// register. -// -//***************************************************************************** -#define USB_RXFUNCADDR3_ADDR_M 0x0000007F // Device Address -#define USB_RXFUNCADDR3_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXHUBADDR3 -// register. -// -//***************************************************************************** -#define USB_RXHUBADDR3_ADDR_M 0x0000007F // Hub Address -#define USB_RXHUBADDR3_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXHUBPORT3 -// register. -// -//***************************************************************************** -#define USB_RXHUBPORT3_PORT_M 0x0000007F // Hub Port -#define USB_RXHUBPORT3_PORT_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXFUNCADDR4 -// register. -// -//***************************************************************************** -#define USB_TXFUNCADDR4_ADDR_M 0x0000007F // Device Address -#define USB_TXFUNCADDR4_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXHUBADDR4 -// register. -// -//***************************************************************************** -#define USB_TXHUBADDR4_ADDR_M 0x0000007F // Hub Address -#define USB_TXHUBADDR4_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXHUBPORT4 -// register. -// -//***************************************************************************** -#define USB_TXHUBPORT4_PORT_M 0x0000007F // Hub Port -#define USB_TXHUBPORT4_PORT_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXFUNCADDR4 -// register. -// -//***************************************************************************** -#define USB_RXFUNCADDR4_ADDR_M 0x0000007F // Device Address -#define USB_RXFUNCADDR4_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXHUBADDR4 -// register. -// -//***************************************************************************** -#define USB_RXHUBADDR4_ADDR_M 0x0000007F // Hub Address -#define USB_RXHUBADDR4_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXHUBPORT4 -// register. -// -//***************************************************************************** -#define USB_RXHUBPORT4_PORT_M 0x0000007F // Hub Port -#define USB_RXHUBPORT4_PORT_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXFUNCADDR5 -// register. -// -//***************************************************************************** -#define USB_TXFUNCADDR5_ADDR_M 0x0000007F // Device Address -#define USB_TXFUNCADDR5_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXHUBADDR5 -// register. -// -//***************************************************************************** -#define USB_TXHUBADDR5_ADDR_M 0x0000007F // Hub Address -#define USB_TXHUBADDR5_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXHUBPORT5 -// register. -// -//***************************************************************************** -#define USB_TXHUBPORT5_PORT_M 0x0000007F // Hub Port -#define USB_TXHUBPORT5_PORT_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXFUNCADDR5 -// register. -// -//***************************************************************************** -#define USB_RXFUNCADDR5_ADDR_M 0x0000007F // Device Address -#define USB_RXFUNCADDR5_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXHUBADDR5 -// register. -// -//***************************************************************************** -#define USB_RXHUBADDR5_ADDR_M 0x0000007F // Hub Address -#define USB_RXHUBADDR5_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXHUBPORT5 -// register. -// -//***************************************************************************** -#define USB_RXHUBPORT5_PORT_M 0x0000007F // Hub Port -#define USB_RXHUBPORT5_PORT_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXFUNCADDR6 -// register. -// -//***************************************************************************** -#define USB_TXFUNCADDR6_ADDR_M 0x0000007F // Device Address -#define USB_TXFUNCADDR6_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXHUBADDR6 -// register. -// -//***************************************************************************** -#define USB_TXHUBADDR6_ADDR_M 0x0000007F // Hub Address -#define USB_TXHUBADDR6_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXHUBPORT6 -// register. -// -//***************************************************************************** -#define USB_TXHUBPORT6_PORT_M 0x0000007F // Hub Port -#define USB_TXHUBPORT6_PORT_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXFUNCADDR6 -// register. -// -//***************************************************************************** -#define USB_RXFUNCADDR6_ADDR_M 0x0000007F // Device Address -#define USB_RXFUNCADDR6_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXHUBADDR6 -// register. -// -//***************************************************************************** -#define USB_RXHUBADDR6_ADDR_M 0x0000007F // Hub Address -#define USB_RXHUBADDR6_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXHUBPORT6 -// register. -// -//***************************************************************************** -#define USB_RXHUBPORT6_PORT_M 0x0000007F // Hub Port -#define USB_RXHUBPORT6_PORT_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXFUNCADDR7 -// register. -// -//***************************************************************************** -#define USB_TXFUNCADDR7_ADDR_M 0x0000007F // Device Address -#define USB_TXFUNCADDR7_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXHUBADDR7 -// register. -// -//***************************************************************************** -#define USB_TXHUBADDR7_ADDR_M 0x0000007F // Hub Address -#define USB_TXHUBADDR7_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXHUBPORT7 -// register. -// -//***************************************************************************** -#define USB_TXHUBPORT7_PORT_M 0x0000007F // Hub Port -#define USB_TXHUBPORT7_PORT_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXFUNCADDR7 -// register. -// -//***************************************************************************** -#define USB_RXFUNCADDR7_ADDR_M 0x0000007F // Device Address -#define USB_RXFUNCADDR7_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXHUBADDR7 -// register. -// -//***************************************************************************** -#define USB_RXHUBADDR7_ADDR_M 0x0000007F // Hub Address -#define USB_RXHUBADDR7_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXHUBPORT7 -// register. -// -//***************************************************************************** -#define USB_RXHUBPORT7_PORT_M 0x0000007F // Hub Port -#define USB_RXHUBPORT7_PORT_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_CSRL0 register. -// -//***************************************************************************** -#define USB_CSRL0_NAKTO 0x00000080 // NAK Timeout -#define USB_CSRL0_SETENDC 0x00000080 // Setup End Clear -#define USB_CSRL0_STATUS 0x00000040 // STATUS Packet -#define USB_CSRL0_RXRDYC 0x00000040 // RXRDY Clear -#define USB_CSRL0_REQPKT 0x00000020 // Request Packet -#define USB_CSRL0_STALL 0x00000020 // Send Stall -#define USB_CSRL0_SETEND 0x00000010 // Setup End -#define USB_CSRL0_ERROR 0x00000010 // Error -#define USB_CSRL0_DATAEND 0x00000008 // Data End -#define USB_CSRL0_SETUP 0x00000008 // Setup Packet -#define USB_CSRL0_STALLED 0x00000004 // Endpoint Stalled -#define USB_CSRL0_TXRDY 0x00000002 // Transmit Packet Ready -#define USB_CSRL0_RXRDY 0x00000001 // Receive Packet Ready - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_CSRH0 register. -// -//***************************************************************************** -#define USB_CSRH0_DISPING 0x00000008 // PING Disable -#define USB_CSRH0_DTWE 0x00000004 // Data Toggle Write Enable -#define USB_CSRH0_DT 0x00000002 // Data Toggle -#define USB_CSRH0_FLUSH 0x00000001 // Flush FIFO - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_COUNT0 register. -// -//***************************************************************************** -#define USB_COUNT0_COUNT_M 0x0000007F // FIFO Count -#define USB_COUNT0_COUNT_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TYPE0 register. -// -//***************************************************************************** -#define USB_TYPE0_SPEED_M 0x000000C0 // Operating Speed -#define USB_TYPE0_SPEED_HIGH 0x00000040 // High -#define USB_TYPE0_SPEED_FULL 0x00000080 // Full -#define USB_TYPE0_SPEED_LOW 0x000000C0 // Low - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_NAKLMT register. -// -//***************************************************************************** -#define USB_NAKLMT_NAKLMT_M 0x0000001F // EP0 NAK Limit -#define USB_NAKLMT_NAKLMT_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXMAXP1 register. -// -//***************************************************************************** -#define USB_TXMAXP1_MAXLOAD_M 0x000007FF // Maximum Payload -#define USB_TXMAXP1_MAXLOAD_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXCSRL1 register. -// -//***************************************************************************** -#define USB_TXCSRL1_NAKTO 0x00000080 // NAK Timeout -#define USB_TXCSRL1_CLRDT 0x00000040 // Clear Data Toggle -#define USB_TXCSRL1_STALLED 0x00000020 // Endpoint Stalled -#define USB_TXCSRL1_STALL 0x00000010 // Send STALL -#define USB_TXCSRL1_SETUP 0x00000010 // Setup Packet -#define USB_TXCSRL1_FLUSH 0x00000008 // Flush FIFO -#define USB_TXCSRL1_ERROR 0x00000004 // Error -#define USB_TXCSRL1_UNDRN 0x00000004 // Underrun -#define USB_TXCSRL1_FIFONE 0x00000002 // FIFO Not Empty -#define USB_TXCSRL1_TXRDY 0x00000001 // Transmit Packet Ready +#ifndef __IO + #define __IO volatile +#endif -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXCSRH1 register. -// -//***************************************************************************** -#define USB_TXCSRH1_AUTOSET 0x00000080 // Auto Set -#define USB_TXCSRH1_ISO 0x00000040 // Isochronous Transfers -#define USB_TXCSRH1_MODE 0x00000020 // Mode -#define USB_TXCSRH1_DMAEN 0x00000010 // DMA Request Enable -#define USB_TXCSRH1_FDT 0x00000008 // Force Data Toggle -#define USB_TXCSRH1_DMAMOD 0x00000004 // DMA Request Mode -#define USB_TXCSRH1_DTWE 0x00000002 // Data Toggle Write Enable -#define USB_TXCSRH1_DT 0x00000001 // Data Toggle +#ifndef __I + #define __I volatile const +#endif -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXMAXP1 register. -// -//***************************************************************************** -#define USB_RXMAXP1_MAXLOAD_M 0x000007FF // Maximum Payload -#define USB_RXMAXP1_MAXLOAD_S 0 +#ifndef __O + #define __O volatile +#endif -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXCSRL1 register. -// -//***************************************************************************** -#define USB_RXCSRL1_CLRDT 0x00000080 // Clear Data Toggle -#define USB_RXCSRL1_STALLED 0x00000040 // Endpoint Stalled -#define USB_RXCSRL1_STALL 0x00000020 // Send STALL -#define USB_RXCSRL1_REQPKT 0x00000020 // Request Packet -#define USB_RXCSRL1_FLUSH 0x00000010 // Flush FIFO -#define USB_RXCSRL1_DATAERR 0x00000008 // Data Error -#define USB_RXCSRL1_NAKTO 0x00000008 // NAK Timeout -#define USB_RXCSRL1_OVER 0x00000004 // Overrun -#define USB_RXCSRL1_ERROR 0x00000004 // Error -#define USB_RXCSRL1_FULL 0x00000002 // FIFO Full -#define USB_RXCSRL1_RXRDY 0x00000001 // Receive Packet Ready +#ifndef __R + #define __R volatile const +#endif -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXCSRH1 register. -// -//***************************************************************************** -#define USB_RXCSRH1_AUTOCL 0x00000080 // Auto Clear -#define USB_RXCSRH1_AUTORQ 0x00000040 // Auto Request -#define USB_RXCSRH1_ISO 0x00000040 // Isochronous Transfers -#define USB_RXCSRH1_DMAEN 0x00000020 // DMA Request Enable -#define USB_RXCSRH1_DISNYET 0x00000010 // Disable NYET -#define USB_RXCSRH1_PIDERR 0x00000010 // PID Error -#define USB_RXCSRH1_DMAMOD 0x00000008 // DMA Request Mode -#define USB_RXCSRH1_DTWE 0x00000004 // Data Toggle Write Enable -#define USB_RXCSRH1_DT 0x00000002 // Data Toggle -#define USB_RXCSRH1_INCOMPRX 0x00000001 // Incomplete RX Transmission - // Status +typedef struct TU_ATTR_PACKED { + __IO uint16_t maxp; // 0x00, 0x04: MAXP + __IO uint8_t csrl; // 0x02, 0x06: CSRL + __IO uint8_t csrh; // 0x03, 0x07: CSRH +}musb_ep_maxp_csr_t; -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXCOUNT1 register. -// -//***************************************************************************** -#define USB_RXCOUNT1_COUNT_M 0x00001FFF // Receive Packet Count -#define USB_RXCOUNT1_COUNT_S 0 +// 0: TX (device IN, host OUT) +// 1: RX (device OUT, host IN) +typedef struct TU_ATTR_PACKED { + union { + struct { + __IO uint16_t tx_maxp; // 0x00: TXMAXP + union { + __IO uint8_t csr0l; // 0x02: CSR0 + __IO uint8_t tx_csrl; // 0x02: TX CSRL + }; + union { + __IO uint8_t csr0h; // 0x03: CSR0H + __IO uint8_t tx_csrh; // 0x03: TX CSRH + }; -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXTYPE1 register. -// -//***************************************************************************** -#define USB_TXTYPE1_SPEED_M 0x000000C0 // Operating Speed -#define USB_TXTYPE1_SPEED_DFLT 0x00000000 // Default -#define USB_TXTYPE1_SPEED_HIGH 0x00000040 // High -#define USB_TXTYPE1_SPEED_FULL 0x00000080 // Full -#define USB_TXTYPE1_SPEED_LOW 0x000000C0 // Low -#define USB_TXTYPE1_PROTO_M 0x00000030 // Protocol -#define USB_TXTYPE1_PROTO_CTRL 0x00000000 // Control -#define USB_TXTYPE1_PROTO_ISOC 0x00000010 // Isochronous -#define USB_TXTYPE1_PROTO_BULK 0x00000020 // Bulk -#define USB_TXTYPE1_PROTO_INT 0x00000030 // Interrupt -#define USB_TXTYPE1_TEP_M 0x0000000F // Target Endpoint Number -#define USB_TXTYPE1_TEP_S 0 + __IO uint16_t rx_maxp; // 0x04: RX MAXP + __IO uint8_t rx_csrl; // 0x06: RX CSRL + __IO uint8_t rx_csrh; // 0x07: RX CSRH + }; -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXINTERVAL1 -// register. -// -//***************************************************************************** -#define USB_TXINTERVAL1_NAKLMT_M \ - 0x000000FF // NAK Limit -#define USB_TXINTERVAL1_TXPOLL_M \ - 0x000000FF // TX Polling -#define USB_TXINTERVAL1_TXPOLL_S \ - 0 -#define USB_TXINTERVAL1_NAKLMT_S \ - 0 + musb_ep_maxp_csr_t maxp_csr[2]; + }; -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXTYPE1 register. -// -//***************************************************************************** -#define USB_RXTYPE1_SPEED_M 0x000000C0 // Operating Speed -#define USB_RXTYPE1_SPEED_DFLT 0x00000000 // Default -#define USB_RXTYPE1_SPEED_HIGH 0x00000040 // High -#define USB_RXTYPE1_SPEED_FULL 0x00000080 // Full -#define USB_RXTYPE1_SPEED_LOW 0x000000C0 // Low -#define USB_RXTYPE1_PROTO_M 0x00000030 // Protocol -#define USB_RXTYPE1_PROTO_CTRL 0x00000000 // Control -#define USB_RXTYPE1_PROTO_ISOC 0x00000010 // Isochronous -#define USB_RXTYPE1_PROTO_BULK 0x00000020 // Bulk -#define USB_RXTYPE1_PROTO_INT 0x00000030 // Interrupt -#define USB_RXTYPE1_TEP_M 0x0000000F // Target Endpoint Number -#define USB_RXTYPE1_TEP_S 0 + union { + __IO uint16_t count0; // 0x08: COUNT0 + __IO uint16_t rx_count; // 0x08: RX COUNT + }; + union { + __IO uint8_t type0; // 0x0A: TYPE0 (host only) + __IO uint8_t tx_type; // 0x0A: TX TYPE + }; + __IO uint8_t tx_interval; // 0x0B: TX INTERVAL + __IO uint8_t rx_type; // 0x0C: RX TYPE + __IO uint8_t rx_interval; // 0x0D: RX INTERVAL + __IO uint8_t reserved_0x0e; // 0x0E: Reserved + union { + __IO uint8_t config_data0; // 0x0F: CONFIG DATA + struct { + __IO uint8_t utmi_data_width : 1; // [0] UTMI Data Width + __IO uint8_t softconn_en : 1; // [1] Soft Connect Enable + __IO uint8_t dynamic_fifo : 1; // [2] Dynamic FIFO Sizing + __IO uint8_t hb_tx_en : 1; // [3] High Bandwidth TX ISO Enable + __IO uint8_t hb_rx_en : 1; // [4] High Bandwidth RX ISO Enable + __IO uint8_t big_endian : 1; // [5] Big Endian + __IO uint8_t mp_tx_en : 1; // [6] Auto splitting BULK TX Enable + __IO uint8_t mp_rx_en : 1; // [7] Auto amalgamation BULK RX Enable + } config_data0_bit; -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXINTERVAL1 -// register. -// -//***************************************************************************** -#define USB_RXINTERVAL1_TXPOLL_M \ - 0x000000FF // RX Polling -#define USB_RXINTERVAL1_NAKLMT_M \ - 0x000000FF // NAK Limit -#define USB_RXINTERVAL1_TXPOLL_S \ - 0 -#define USB_RXINTERVAL1_NAKLMT_S \ - 0 + __IO uint8_t fifo_size; // 0x0F: FIFO_SIZE + struct { + __IO uint8_t tx : 4; // [3:0] TX FIFO Size + __IO uint8_t rx : 4; // [7:4] RX FIFO Size + }fifo_size_bit; + }; +} musb_ep_csr_t; -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXMAXP2 register. -// -//***************************************************************************** -#define USB_TXMAXP2_MAXLOAD_M 0x000007FF // Maximum Payload -#define USB_TXMAXP2_MAXLOAD_S 0 +TU_VERIFY_STATIC(sizeof(musb_ep_csr_t) == 16, "size is not correct"); -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXCSRL2 register. -// -//***************************************************************************** -#define USB_TXCSRL2_NAKTO 0x00000080 // NAK Timeout -#define USB_TXCSRL2_CLRDT 0x00000040 // Clear Data Toggle -#define USB_TXCSRL2_STALLED 0x00000020 // Endpoint Stalled -#define USB_TXCSRL2_SETUP 0x00000010 // Setup Packet -#define USB_TXCSRL2_STALL 0x00000010 // Send STALL -#define USB_TXCSRL2_FLUSH 0x00000008 // Flush FIFO -#define USB_TXCSRL2_ERROR 0x00000004 // Error -#define USB_TXCSRL2_UNDRN 0x00000004 // Underrun -#define USB_TXCSRL2_FIFONE 0x00000002 // FIFO Not Empty -#define USB_TXCSRL2_TXRDY 0x00000001 // Transmit Packet Ready +typedef struct TU_ATTR_PACKED { + //------------- Common -------------// + __IO uint8_t faddr; // 0x00: FADDR + union { + __IO uint8_t power; // 0x01: POWER + struct { + __IO uint8_t suspend_mode_en : 1; // [0] SUSPEND Mode Enable + __IO uint8_t suspend_mode : 1; // [1] SUSPEND Mode + __IO uint8_t resume_mode : 1; // [2] RESUME + __IO uint8_t reset : 1; // [3] RESET + __IO uint8_t highspeed_mode : 1; // [4] High Speed Mode + __IO uint8_t highspeed_en : 1; // [5] High Speed Enable + __IO uint8_t soft_conn : 1; // [6] Soft Connect/Disconnect + __IO uint8_t iso_update : 1; // [7] Isochronous Update + } power_bit; + }; -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXCSRH2 register. -// -//***************************************************************************** -#define USB_TXCSRH2_AUTOSET 0x00000080 // Auto Set -#define USB_TXCSRH2_ISO 0x00000040 // Isochronous Transfers -#define USB_TXCSRH2_MODE 0x00000020 // Mode -#define USB_TXCSRH2_DMAEN 0x00000010 // DMA Request Enable -#define USB_TXCSRH2_FDT 0x00000008 // Force Data Toggle -#define USB_TXCSRH2_DMAMOD 0x00000004 // DMA Request Mode -#define USB_TXCSRH2_DTWE 0x00000002 // Data Toggle Write Enable -#define USB_TXCSRH2_DT 0x00000001 // Data Toggle + union { + struct { + __IO uint16_t intr_tx; // 0x02: INTR_TX + __IO uint16_t intr_rx; // 0x04: INTR_RX + }; -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXMAXP2 register. -// -//***************************************************************************** -#define USB_RXMAXP2_MAXLOAD_M 0x000007FF // Maximum Payload -#define USB_RXMAXP2_MAXLOAD_S 0 + __IO uint16_t intr_ep[2]; // 0x02-0x05: INTR_EP0-1 + }; -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXCSRL2 register. -// -//***************************************************************************** -#define USB_RXCSRL2_CLRDT 0x00000080 // Clear Data Toggle -#define USB_RXCSRL2_STALLED 0x00000040 // Endpoint Stalled -#define USB_RXCSRL2_REQPKT 0x00000020 // Request Packet -#define USB_RXCSRL2_STALL 0x00000020 // Send STALL -#define USB_RXCSRL2_FLUSH 0x00000010 // Flush FIFO -#define USB_RXCSRL2_DATAERR 0x00000008 // Data Error -#define USB_RXCSRL2_NAKTO 0x00000008 // NAK Timeout -#define USB_RXCSRL2_ERROR 0x00000004 // Error -#define USB_RXCSRL2_OVER 0x00000004 // Overrun -#define USB_RXCSRL2_FULL 0x00000002 // FIFO Full -#define USB_RXCSRL2_RXRDY 0x00000001 // Receive Packet Ready + union { + struct { + __IO uint16_t intr_txen; // 0x06: INTR_TXEN + __IO uint16_t intr_rxen; // 0x08: INTR_RXEN + }; -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXCSRH2 register. -// -//***************************************************************************** -#define USB_RXCSRH2_AUTOCL 0x00000080 // Auto Clear -#define USB_RXCSRH2_AUTORQ 0x00000040 // Auto Request -#define USB_RXCSRH2_ISO 0x00000040 // Isochronous Transfers -#define USB_RXCSRH2_DMAEN 0x00000020 // DMA Request Enable -#define USB_RXCSRH2_DISNYET 0x00000010 // Disable NYET -#define USB_RXCSRH2_PIDERR 0x00000010 // PID Error -#define USB_RXCSRH2_DMAMOD 0x00000008 // DMA Request Mode -#define USB_RXCSRH2_DTWE 0x00000004 // Data Toggle Write Enable -#define USB_RXCSRH2_DT 0x00000002 // Data Toggle -#define USB_RXCSRH2_INCOMPRX 0x00000001 // Incomplete RX Transmission - // Status + __IO uint16_t intren_ep[2]; // 0x06-0x09: INTREN_EP0-1 + }; -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXCOUNT2 register. -// -//***************************************************************************** -#define USB_RXCOUNT2_COUNT_M 0x00001FFF // Receive Packet Count -#define USB_RXCOUNT2_COUNT_S 0 + __IO uint8_t intr_usb; // 0x0A: INTRUSB + __IO uint8_t intr_usben; // 0x0B: INTRUSBEN -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXTYPE2 register. -// -//***************************************************************************** -#define USB_TXTYPE2_SPEED_M 0x000000C0 // Operating Speed -#define USB_TXTYPE2_SPEED_DFLT 0x00000000 // Default -#define USB_TXTYPE2_SPEED_HIGH 0x00000040 // High -#define USB_TXTYPE2_SPEED_FULL 0x00000080 // Full -#define USB_TXTYPE2_SPEED_LOW 0x000000C0 // Low -#define USB_TXTYPE2_PROTO_M 0x00000030 // Protocol -#define USB_TXTYPE2_PROTO_CTRL 0x00000000 // Control -#define USB_TXTYPE2_PROTO_ISOC 0x00000010 // Isochronous -#define USB_TXTYPE2_PROTO_BULK 0x00000020 // Bulk -#define USB_TXTYPE2_PROTO_INT 0x00000030 // Interrupt -#define USB_TXTYPE2_TEP_M 0x0000000F // Target Endpoint Number -#define USB_TXTYPE2_TEP_S 0 + __IO uint16_t frame; // 0x0C: FRAME + __IO uint8_t index; // 0x0E: INDEX + __IO uint8_t testmode; // 0x0F: TESTMODE -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXINTERVAL2 -// register. -// -//***************************************************************************** -#define USB_TXINTERVAL2_TXPOLL_M \ - 0x000000FF // TX Polling -#define USB_TXINTERVAL2_NAKLMT_M \ - 0x000000FF // NAK Limit -#define USB_TXINTERVAL2_NAKLMT_S \ - 0 -#define USB_TXINTERVAL2_TXPOLL_S \ - 0 + //------------- Endpoint CSR (indexed) -------------// + musb_ep_csr_t indexed_csr; // 0x10-0x1F: Indexed CSR 0-15 -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXTYPE2 register. -// -//***************************************************************************** -#define USB_RXTYPE2_SPEED_M 0x000000C0 // Operating Speed -#define USB_RXTYPE2_SPEED_DFLT 0x00000000 // Default -#define USB_RXTYPE2_SPEED_HIGH 0x00000040 // High -#define USB_RXTYPE2_SPEED_FULL 0x00000080 // Full -#define USB_RXTYPE2_SPEED_LOW 0x000000C0 // Low -#define USB_RXTYPE2_PROTO_M 0x00000030 // Protocol -#define USB_RXTYPE2_PROTO_CTRL 0x00000000 // Control -#define USB_RXTYPE2_PROTO_ISOC 0x00000010 // Isochronous -#define USB_RXTYPE2_PROTO_BULK 0x00000020 // Bulk -#define USB_RXTYPE2_PROTO_INT 0x00000030 // Interrupt -#define USB_RXTYPE2_TEP_M 0x0000000F // Target Endpoint Number -#define USB_RXTYPE2_TEP_S 0 + //------------- FIFOs -------------// + __IO uint32_t fifo[16]; // 0x20-0x5C: FIFO 0-15 -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXINTERVAL2 -// register. -// -//***************************************************************************** -#define USB_RXINTERVAL2_TXPOLL_M \ - 0x000000FF // RX Polling -#define USB_RXINTERVAL2_NAKLMT_M \ - 0x000000FF // NAK Limit -#define USB_RXINTERVAL2_TXPOLL_S \ - 0 -#define USB_RXINTERVAL2_NAKLMT_S \ - 0 + // Common (2) + __IO uint8_t devctl; // 0x60: DEVCTL + __IO uint8_t misc; // 0x61: MISC -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXMAXP3 register. -// -//***************************************************************************** -#define USB_TXMAXP3_MAXLOAD_M 0x000007FF // Maximum Payload -#define USB_TXMAXP3_MAXLOAD_S 0 + //------------- Dynammic FIFO (indexed) -------------// + union { + struct { + __IO uint8_t txfifo_sz; // 0x62: TXFIFO_SZ + __IO uint8_t rxfifo_sz; // 0x63: RXFIFO_SZ + }; + __IO uint8_t fifo_size[2]; + }; -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXCSRL3 register. -// -//***************************************************************************** -#define USB_TXCSRL3_NAKTO 0x00000080 // NAK Timeout -#define USB_TXCSRL3_CLRDT 0x00000040 // Clear Data Toggle -#define USB_TXCSRL3_STALLED 0x00000020 // Endpoint Stalled -#define USB_TXCSRL3_SETUP 0x00000010 // Setup Packet -#define USB_TXCSRL3_STALL 0x00000010 // Send STALL -#define USB_TXCSRL3_FLUSH 0x00000008 // Flush FIFO -#define USB_TXCSRL3_ERROR 0x00000004 // Error -#define USB_TXCSRL3_UNDRN 0x00000004 // Underrun -#define USB_TXCSRL3_FIFONE 0x00000002 // FIFO Not Empty -#define USB_TXCSRL3_TXRDY 0x00000001 // Transmit Packet Ready + union { + struct { + __IO uint16_t txfifo_addr; // 0x64: TXFIFO_ADDR + __IO uint16_t rxfifo_addr; // 0x66: RXFIFO_ADDR + }; + __IO uint16_t fifo_addr[2]; + }; -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXCSRH3 register. -// -//***************************************************************************** -#define USB_TXCSRH3_AUTOSET 0x00000080 // Auto Set -#define USB_TXCSRH3_ISO 0x00000040 // Isochronous Transfers -#define USB_TXCSRH3_MODE 0x00000020 // Mode -#define USB_TXCSRH3_DMAEN 0x00000010 // DMA Request Enable -#define USB_TXCSRH3_FDT 0x00000008 // Force Data Toggle -#define USB_TXCSRH3_DMAMOD 0x00000004 // DMA Request Mode -#define USB_TXCSRH3_DTWE 0x00000002 // Data Toggle Write Enable -#define USB_TXCSRH3_DT 0x00000001 // Data Toggle + //------------- Additional Control and Configuration -------------// + union { + __O uint32_t vcontrol; // 0x68: PHY VCONTROL + __IO uint32_t vstatus; // 0x68: PHY VSTATUS + }; + union { + __IO uint16_t hwvers; // 0x6C: HWVERS + struct { + __IO uint16_t minor : 10; // [9:0] Minor + __IO uint16_t major : 5; // [14:10] Major + __IO uint16_t rc : 1; // [15] Release Candidate + } hwvers_bit; + }; + __R uint16_t rsv_0x6e_0x77[5]; // 0x6E-0x77: Reserved -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXMAXP3 register. -// -//***************************************************************************** -#define USB_RXMAXP3_MAXLOAD_M 0x000007FF // Maximum Payload -#define USB_RXMAXP3_MAXLOAD_S 0 + //------------- Additional Configuration -------------// + union { + __IO uint8_t epinfo; // 0x78: EPINFO + struct { + __IO uint8_t tx_ep_num : 4; // [3:0] TX Endpoints + __IO uint8_t rx_ep_num : 4; // [7:4] RX Endpoints + } epinfo_bit; + }; + union { + __IO uint8_t raminfo; // 0x79: RAMINFO + struct { + __IO uint8_t ram_bits : 4; // [3:0] RAM Address Bus Width + __IO uint8_t dma_channel : 4; // [7:4] DMA Channels + }raminfo_bit; + }; + union { + __IO uint8_t link_info; // 0x7A: LINK_INFO + __IO uint8_t adi_softreset; // 0x7A: AnalogDevice SOFTRESET + }; + __IO uint8_t vplen; // 0x7B: VPLEN + __IO uint8_t hs_eof1; // 0x7C: HS_EOF1 + __IO uint8_t fs_eof1; // 0x7D: FS_EOF1 + __IO uint8_t ls_eof1; // 0x7E: LS_EOF1 + __IO uint8_t soft_rst; // 0x7F: SOFT_RST -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXCSRL3 register. -// -//***************************************************************************** -#define USB_RXCSRL3_CLRDT 0x00000080 // Clear Data Toggle -#define USB_RXCSRL3_STALLED 0x00000040 // Endpoint Stalled -#define USB_RXCSRL3_STALL 0x00000020 // Send STALL -#define USB_RXCSRL3_REQPKT 0x00000020 // Request Packet -#define USB_RXCSRL3_FLUSH 0x00000010 // Flush FIFO -#define USB_RXCSRL3_DATAERR 0x00000008 // Data Error -#define USB_RXCSRL3_NAKTO 0x00000008 // NAK Timeout -#define USB_RXCSRL3_ERROR 0x00000004 // Error -#define USB_RXCSRL3_OVER 0x00000004 // Overrun -#define USB_RXCSRL3_FULL 0x00000002 // FIFO Full -#define USB_RXCSRL3_RXRDY 0x00000001 // Receive Packet Ready + //------------- Target Endpoints (multipoint option) -------------// + __IO uint16_t ctuch; // 0x80: CTUCH + __IO uint16_t cthsrtn; // 0x82: CTHSRTN + __R uint32_t rsv_0x84_0xff[31]; // 0x84-0xFF: Reserved -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXCSRH3 register. -// -//***************************************************************************** -#define USB_RXCSRH3_AUTOCL 0x00000080 // Auto Clear -#define USB_RXCSRH3_AUTORQ 0x00000040 // Auto Request -#define USB_RXCSRH3_ISO 0x00000040 // Isochronous Transfers -#define USB_RXCSRH3_DMAEN 0x00000020 // DMA Request Enable -#define USB_RXCSRH3_DISNYET 0x00000010 // Disable NYET -#define USB_RXCSRH3_PIDERR 0x00000010 // PID Error -#define USB_RXCSRH3_DMAMOD 0x00000008 // DMA Request Mode -#define USB_RXCSRH3_DTWE 0x00000004 // Data Toggle Write Enable -#define USB_RXCSRH3_DT 0x00000002 // Data Toggle -#define USB_RXCSRH3_INCOMPRX 0x00000001 // Incomplete RX Transmission - // Status + //------------- Non-Indexed Endpoint CSRs -------------// + // TI tm4c can access this directly, but should use indexed_csr for portability + musb_ep_csr_t abs_csr[16]; // 0x100-0x1FF: EP0-15 CSR -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXCOUNT3 register. -// -//***************************************************************************** -#define USB_RXCOUNT3_COUNT_M 0x00001FFF // Receive Packet Count -#define USB_RXCOUNT3_COUNT_S 0 + //------------- DMA -------------// + __IO uint8_t dma_intr; // 0x200: DMA_INTR + __R uint8_t rsv_0x201_0x203[3]; // 0x201-0x203: Reserved + struct { + __IO uint16_t cntl; // 0x204: DMA_CNTL + __IO uint16_t rsv_0x206; // 0x206: Reserved + __IO uint32_t addr; // 0x208: DMA_ADDR + __IO uint32_t count; // 0x20C: DMA_COUNT + __IO uint32_t rsv_0x210; // 0x210: Reserved + }dma[8]; + __R uint32_t rsv_0x284_0x2FF[31]; // 0x284-0x2FF: Reserved -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXTYPE3 register. -// -//***************************************************************************** -#define USB_TXTYPE3_SPEED_M 0x000000C0 // Operating Speed -#define USB_TXTYPE3_SPEED_DFLT 0x00000000 // Default -#define USB_TXTYPE3_SPEED_HIGH 0x00000040 // High -#define USB_TXTYPE3_SPEED_FULL 0x00000080 // Full -#define USB_TXTYPE3_SPEED_LOW 0x000000C0 // Low -#define USB_TXTYPE3_PROTO_M 0x00000030 // Protocol -#define USB_TXTYPE3_PROTO_CTRL 0x00000000 // Control -#define USB_TXTYPE3_PROTO_ISOC 0x00000010 // Isochronous -#define USB_TXTYPE3_PROTO_BULK 0x00000020 // Bulk -#define USB_TXTYPE3_PROTO_INT 0x00000030 // Interrupt -#define USB_TXTYPE3_TEP_M 0x0000000F // Target Endpoint Number -#define USB_TXTYPE3_TEP_S 0 + //------------- Extended -------------// + __R uint32_t rsv_0x300; // 0x300: Reserved + struct { + __IO uint16_t count; // 0x304: REQ_PACKET_COUNT + __R uint16_t rsv_0x306; // 0x306: Reserved + }req_packet[15]; -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXINTERVAL3 -// register. -// -//***************************************************************************** -#define USB_TXINTERVAL3_TXPOLL_M \ - 0x000000FF // TX Polling -#define USB_TXINTERVAL3_NAKLMT_M \ - 0x000000FF // NAK Limit -#define USB_TXINTERVAL3_TXPOLL_S \ - 0 -#define USB_TXINTERVAL3_NAKLMT_S \ - 0 + __IO uint16_t rx_doulbe_packet_disable; // 0x340: RX_DOUBLE_PACKET_DISABLE + __IO uint16_t tx_double_packet_disable; // 0x342: TX_DOUBLE_PACKET_DISABLE -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXTYPE3 register. -// -//***************************************************************************** -#define USB_RXTYPE3_SPEED_M 0x000000C0 // Operating Speed -#define USB_RXTYPE3_SPEED_DFLT 0x00000000 // Default -#define USB_RXTYPE3_SPEED_HIGH 0x00000040 // High -#define USB_RXTYPE3_SPEED_FULL 0x00000080 // Full -#define USB_RXTYPE3_SPEED_LOW 0x000000C0 // Low -#define USB_RXTYPE3_PROTO_M 0x00000030 // Protocol -#define USB_RXTYPE3_PROTO_CTRL 0x00000000 // Control -#define USB_RXTYPE3_PROTO_ISOC 0x00000010 // Isochronous -#define USB_RXTYPE3_PROTO_BULK 0x00000020 // Bulk -#define USB_RXTYPE3_PROTO_INT 0x00000030 // Interrupt -#define USB_RXTYPE3_TEP_M 0x0000000F // Target Endpoint Number -#define USB_RXTYPE3_TEP_S 0 + __IO uint16_t chirp_timeout; // 0x344: CHIRP_TIMEOUT + __IO uint16_t hs_to_utm; // 0x346: HS_TO_UTM delay + __IO uint16_t hs_timeout_adder; // 0x348: HS_TIMEOUT_ADDER -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXINTERVAL3 -// register. -// -//***************************************************************************** -#define USB_RXINTERVAL3_TXPOLL_M \ - 0x000000FF // RX Polling -#define USB_RXINTERVAL3_NAKLMT_M \ - 0x000000FF // NAK Limit -#define USB_RXINTERVAL3_TXPOLL_S \ - 0 -#define USB_RXINTERVAL3_NAKLMT_S \ - 0 + __R uint8_t rsv_34A_34f[6]; // 0x34A-0x34F: Reserved +} musb_regs_t; -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXMAXP4 register. -// -//***************************************************************************** -#define USB_TXMAXP4_MAXLOAD_M 0x000007FF // Maximum Payload -#define USB_TXMAXP4_MAXLOAD_S 0 +TU_VERIFY_STATIC(sizeof(musb_regs_t) == 0x350, "size is not correct"); -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXCSRL4 register. -// -//***************************************************************************** -#define USB_TXCSRL4_NAKTO 0x00000080 // NAK Timeout -#define USB_TXCSRL4_CLRDT 0x00000040 // Clear Data Toggle -#define USB_TXCSRL4_STALLED 0x00000020 // Endpoint Stalled -#define USB_TXCSRL4_SETUP 0x00000010 // Setup Packet -#define USB_TXCSRL4_STALL 0x00000010 // Send STALL -#define USB_TXCSRL4_FLUSH 0x00000008 // Flush FIFO -#define USB_TXCSRL4_ERROR 0x00000004 // Error -#define USB_TXCSRL4_UNDRN 0x00000004 // Underrun -#define USB_TXCSRL4_FIFONE 0x00000002 // FIFO Not Empty -#define USB_TXCSRL4_TXRDY 0x00000001 // Transmit Packet Ready +//--------------------------------------------------------------------+ +// Helper +//--------------------------------------------------------------------+ +TU_ATTR_ALWAYS_INLINE static inline musb_ep_csr_t* get_ep_csr(musb_regs_t* musb_regs, unsigned epnum) { + musb_regs->index = epnum; + return &musb_regs->indexed_csr; +} -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXCSRH4 register. -// -//***************************************************************************** -#define USB_TXCSRH4_AUTOSET 0x00000080 // Auto Set -#define USB_TXCSRH4_ISO 0x00000040 // Isochronous Transfers -#define USB_TXCSRH4_MODE 0x00000020 // Mode -#define USB_TXCSRH4_DMAEN 0x00000010 // DMA Request Enable -#define USB_TXCSRH4_FDT 0x00000008 // Force Data Toggle -#define USB_TXCSRH4_DMAMOD 0x00000004 // DMA Request Mode -#define USB_TXCSRH4_DTWE 0x00000002 // Data Toggle Write Enable -#define USB_TXCSRH4_DT 0x00000001 // Data Toggle +//--------------------------------------------------------------------+ +// Register Bit Field +//--------------------------------------------------------------------+ -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXMAXP4 register. -// -//***************************************************************************** -#define USB_RXMAXP4_MAXLOAD_M 0x000007FF // Maximum Payload -#define USB_RXMAXP4_MAXLOAD_S 0 +// 0x01: Power +#define MUSB_POWER_ISOUP 0x0080 // Isochronous Update +#define MUSB_POWER_SOFTCONN 0x0040 // Soft Connect/Disconnect +#define MUSB_POWER_HSENAB 0x0020 // High Speed Enable +#define MUSB_POWER_HSMODE 0x0010 // High Speed Enable +#define MUSB_POWER_RESET 0x0008 // RESET Signaling +#define MUSB_POWER_RESUME 0x0004 // RESUME Signaling +#define MUSB_POWER_SUSPEND 0x0002 // SUSPEND Mode +#define MUSB_POWER_PWRDNPHY 0x0001 // Power Down PHY -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXCSRL4 register. -// -//***************************************************************************** -#define USB_RXCSRL4_CLRDT 0x00000080 // Clear Data Toggle -#define USB_RXCSRL4_STALLED 0x00000040 // Endpoint Stalled -#define USB_RXCSRL4_STALL 0x00000020 // Send STALL -#define USB_RXCSRL4_REQPKT 0x00000020 // Request Packet -#define USB_RXCSRL4_FLUSH 0x00000010 // Flush FIFO -#define USB_RXCSRL4_NAKTO 0x00000008 // NAK Timeout -#define USB_RXCSRL4_DATAERR 0x00000008 // Data Error -#define USB_RXCSRL4_OVER 0x00000004 // Overrun -#define USB_RXCSRL4_ERROR 0x00000004 // Error -#define USB_RXCSRL4_FULL 0x00000002 // FIFO Full -#define USB_RXCSRL4_RXRDY 0x00000001 // Receive Packet Ready - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXCSRH4 register. -// -//***************************************************************************** -#define USB_RXCSRH4_AUTOCL 0x00000080 // Auto Clear -#define USB_RXCSRH4_AUTORQ 0x00000040 // Auto Request -#define USB_RXCSRH4_ISO 0x00000040 // Isochronous Transfers -#define USB_RXCSRH4_DMAEN 0x00000020 // DMA Request Enable -#define USB_RXCSRH4_DISNYET 0x00000010 // Disable NYET -#define USB_RXCSRH4_PIDERR 0x00000010 // PID Error -#define USB_RXCSRH4_DMAMOD 0x00000008 // DMA Request Mode -#define USB_RXCSRH4_DTWE 0x00000004 // Data Toggle Write Enable -#define USB_RXCSRH4_DT 0x00000002 // Data Toggle -#define USB_RXCSRH4_INCOMPRX 0x00000001 // Incomplete RX Transmission - // Status - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXCOUNT4 register. -// -//***************************************************************************** -#define USB_RXCOUNT4_COUNT_M 0x00001FFF // Receive Packet Count -#define USB_RXCOUNT4_COUNT_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXTYPE4 register. -// -//***************************************************************************** -#define USB_TXTYPE4_SPEED_M 0x000000C0 // Operating Speed -#define USB_TXTYPE4_SPEED_DFLT 0x00000000 // Default -#define USB_TXTYPE4_SPEED_HIGH 0x00000040 // High -#define USB_TXTYPE4_SPEED_FULL 0x00000080 // Full -#define USB_TXTYPE4_SPEED_LOW 0x000000C0 // Low -#define USB_TXTYPE4_PROTO_M 0x00000030 // Protocol -#define USB_TXTYPE4_PROTO_CTRL 0x00000000 // Control -#define USB_TXTYPE4_PROTO_ISOC 0x00000010 // Isochronous -#define USB_TXTYPE4_PROTO_BULK 0x00000020 // Bulk -#define USB_TXTYPE4_PROTO_INT 0x00000030 // Interrupt -#define USB_TXTYPE4_TEP_M 0x0000000F // Target Endpoint Number -#define USB_TXTYPE4_TEP_S 0 +// Interrupt TX/RX Status and Enable: each bit is for an endpoint -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXINTERVAL4 -// register. -// -//***************************************************************************** -#define USB_TXINTERVAL4_TXPOLL_M \ - 0x000000FF // TX Polling -#define USB_TXINTERVAL4_NAKLMT_M \ - 0x000000FF // NAK Limit -#define USB_TXINTERVAL4_NAKLMT_S \ - 0 -#define USB_TXINTERVAL4_TXPOLL_S \ - 0 +// 0x6c: HWVERS +#define MUSB_HWVERS_RC_SHIFT 15 +#define MUSB_HWVERS_RC_MASK 0x8000 +#define MUSB_HWVERS_MAJOR_SHIFT 10 +#define MUSB_HWVERS_MAJOR_MASK 0x7C00 +#define MUSB_HWVERS_MINOR_SHIFT 0 +#define MUSB_HWVERS_MINOR_MASK 0x03FF -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXTYPE4 register. -// -//***************************************************************************** -#define USB_RXTYPE4_SPEED_M 0x000000C0 // Operating Speed -#define USB_RXTYPE4_SPEED_DFLT 0x00000000 // Default -#define USB_RXTYPE4_SPEED_HIGH 0x00000040 // High -#define USB_RXTYPE4_SPEED_FULL 0x00000080 // Full -#define USB_RXTYPE4_SPEED_LOW 0x000000C0 // Low -#define USB_RXTYPE4_PROTO_M 0x00000030 // Protocol -#define USB_RXTYPE4_PROTO_CTRL 0x00000000 // Control -#define USB_RXTYPE4_PROTO_ISOC 0x00000010 // Isochronous -#define USB_RXTYPE4_PROTO_BULK 0x00000020 // Bulk -#define USB_RXTYPE4_PROTO_INT 0x00000030 // Interrupt -#define USB_RXTYPE4_TEP_M 0x0000000F // Target Endpoint Number -#define USB_RXTYPE4_TEP_S 0 +// 0x12, 0x16: TX/RX CSRL +#define MUSB_CSRL_PACKET_READY(_rx) (1u << 0) +#define MUSB_CSRL_FLUSH_FIFO(_rx) (1u << ((_rx) ? 4 : 3)) +#define MUSB_CSRL_SEND_STALL(_rx) (1u << ((_rx) ? 5 : 4)) +#define MUSB_CSRL_STALLED(_rx) (1u << ((_rx) ? 6 : 5)) +#define MUSB_CSRL_CLEAR_DATA_TOGGLE(_rx) (1u << ((_rx) ? 7 : 6)) -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXINTERVAL4 -// register. -// -//***************************************************************************** -#define USB_RXINTERVAL4_TXPOLL_M \ - 0x000000FF // RX Polling -#define USB_RXINTERVAL4_NAKLMT_M \ - 0x000000FF // NAK Limit -#define USB_RXINTERVAL4_NAKLMT_S \ - 0 -#define USB_RXINTERVAL4_TXPOLL_S \ - 0 +// 0x13, 0x17: TX/RX CSRH +#define MUSB_CSRH_DISABLE_DOUBLE_PACKET(_rx) (1u << 1) +#define MUSB_CSRH_TX_MODE (1u << 5) // 1 = TX, 0 = RX. only relevant for SHARED FIFO +#define MUSB_CSRH_ISO (1u << 6) -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXMAXP5 register. -// -//***************************************************************************** -#define USB_TXMAXP5_MAXLOAD_M 0x000007FF // Maximum Payload -#define USB_TXMAXP5_MAXLOAD_S 0 +// 0x62, 0x63: TXFIFO_SZ, RXFIFO_SZ +#define MUSB_FIFOSZ_DOUBLE_PACKET (1u << 4) -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXCSRL5 register. -// -//***************************************************************************** -#define USB_TXCSRL5_NAKTO 0x00000080 // NAK Timeout -#define USB_TXCSRL5_CLRDT 0x00000040 // Clear Data Toggle -#define USB_TXCSRL5_STALLED 0x00000020 // Endpoint Stalled -#define USB_TXCSRL5_SETUP 0x00000010 // Setup Packet -#define USB_TXCSRL5_STALL 0x00000010 // Send STALL -#define USB_TXCSRL5_FLUSH 0x00000008 // Flush FIFO -#define USB_TXCSRL5_ERROR 0x00000004 // Error -#define USB_TXCSRL5_UNDRN 0x00000004 // Underrun -#define USB_TXCSRL5_FIFONE 0x00000002 // FIFO Not Empty -#define USB_TXCSRL5_TXRDY 0x00000001 // Transmit Packet Ready //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_TXCSRH5 register. +// The following are defines for the bit fields in the MUSB_O_IS register. // //***************************************************************************** -#define USB_TXCSRH5_AUTOSET 0x00000080 // Auto Set -#define USB_TXCSRH5_ISO 0x00000040 // Isochronous Transfers -#define USB_TXCSRH5_MODE 0x00000020 // Mode -#define USB_TXCSRH5_DMAEN 0x00000010 // DMA Request Enable -#define USB_TXCSRH5_FDT 0x00000008 // Force Data Toggle -#define USB_TXCSRH5_DMAMOD 0x00000004 // DMA Request Mode -#define USB_TXCSRH5_DTWE 0x00000002 // Data Toggle Write Enable -#define USB_TXCSRH5_DT 0x00000001 // Data Toggle +#define MUSB_IS_VBUSERR 0x0080 // VBUS Error (OTG only) +#define MUSB_IS_SESREQ 0x0040 // SESSION REQUEST (OTG only) +#define MUSB_IS_DISCON 0x0020 // Session Disconnect (OTG only) +#define MUSB_IS_CONN 0x0010 // Session Connect +#define MUSB_IS_SOF 0x0008 // Start of Frame +#define MUSB_IS_BABBLE 0x0004 // Babble Detected +#define MUSB_IS_RESET 0x0004 // RESET Signaling Detected +#define MUSB_IS_RESUME 0x0002 // RESUME Signaling Detected +#define MUSB_IS_SUSPEND 0x0001 // SUSPEND Signaling Detected //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_RXMAXP5 register. +// The following are defines for the bit fields in the MUSB_O_IE register. // //***************************************************************************** -#define USB_RXMAXP5_MAXLOAD_M 0x000007FF // Maximum Payload -#define USB_RXMAXP5_MAXLOAD_S 0 +#define MUSB_IE_VBUSERR 0x0080 // Enable VBUS Error Interrupt (OTG only) +#define MUSB_IE_SESREQ 0x0040 // Enable Session Request (OTG only) +#define MUSB_IE_DISCON 0x0020 // Enable Disconnect Interrupt +#define MUSB_IE_CONN 0x0010 // Enable Connect Interrupt +#define MUSB_IE_SOF 0x0008 // Enable Start-of-Frame Interrupt +#define MUSB_IE_BABBLE 0x0004 // Enable Babble Interrupt +#define MUSB_IE_RESET 0x0004 // Enable RESET Interrupt +#define MUSB_IE_RESUME 0x0002 // Enable RESUME Interrupt +#define MUSB_IE_SUSPND 0x0001 // Enable SUSPEND Interrupt //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_RXCSRL5 register. +// The following are defines for the bit fields in the MUSB_O_FRAME register. // //***************************************************************************** -#define USB_RXCSRL5_CLRDT 0x00000080 // Clear Data Toggle -#define USB_RXCSRL5_STALLED 0x00000040 // Endpoint Stalled -#define USB_RXCSRL5_STALL 0x00000020 // Send STALL -#define USB_RXCSRL5_REQPKT 0x00000020 // Request Packet -#define USB_RXCSRL5_FLUSH 0x00000010 // Flush FIFO -#define USB_RXCSRL5_NAKTO 0x00000008 // NAK Timeout -#define USB_RXCSRL5_DATAERR 0x00000008 // Data Error -#define USB_RXCSRL5_ERROR 0x00000004 // Error -#define USB_RXCSRL5_OVER 0x00000004 // Overrun -#define USB_RXCSRL5_FULL 0x00000002 // FIFO Full -#define USB_RXCSRL5_RXRDY 0x00000001 // Receive Packet Ready +#define MUSB_FRAME_M 0x07FF // Frame Number +#define MUSB_FRAME_S 0 //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_RXCSRH5 register. +// The following are defines for the bit fields in the MUSB_O_TEST register. // //***************************************************************************** -#define USB_RXCSRH5_AUTOCL 0x00000080 // Auto Clear -#define USB_RXCSRH5_AUTORQ 0x00000040 // Auto Request -#define USB_RXCSRH5_ISO 0x00000040 // Isochronous Transfers -#define USB_RXCSRH5_DMAEN 0x00000020 // DMA Request Enable -#define USB_RXCSRH5_DISNYET 0x00000010 // Disable NYET -#define USB_RXCSRH5_PIDERR 0x00000010 // PID Error -#define USB_RXCSRH5_DMAMOD 0x00000008 // DMA Request Mode -#define USB_RXCSRH5_DTWE 0x00000004 // Data Toggle Write Enable -#define USB_RXCSRH5_DT 0x00000002 // Data Toggle -#define USB_RXCSRH5_INCOMPRX 0x00000001 // Incomplete RX Transmission - // Status +#define MUSB_TEST_FORCEH 0x0080 // Force Host Mode +#define MUSB_TEST_FIFOACC 0x0040 // FIFO Access +#define MUSB_TEST_FORCEFS 0x0020 // Force Full-Speed Mode +#define MUSB_TEST_FORCEHS 0x0010 // Force High-Speed Mode +#define MUSB_TEST_TESTPKT 0x0008 // Test Packet Mode Enable +#define MUSB_TEST_TESTK 0x0004 // Test_K Mode Enable +#define MUSB_TEST_TESTJ 0x0002 // Test_J Mode Enable +#define MUSB_TEST_TESTSE0NAK 0x0001 // Test_SE0_NAK Test Mode Enable //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_RXCOUNT5 register. +// The following are defines for the bit fields in the MUSB_O_DEVCTL register. // //***************************************************************************** -#define USB_RXCOUNT5_COUNT_M 0x00001FFF // Receive Packet Count -#define USB_RXCOUNT5_COUNT_S 0 +#define MUSB_DEVCTL_DEV 0x0080 // Device Mode (OTG only) +#define MUSB_DEVCTL_FSDEV 0x0040 // Full-Speed Device Detected +#define MUSB_DEVCTL_LSDEV 0x0020 // Low-Speed Device Detected +#define MUSB_DEVCTL_VBUS_M 0x0018 // VBUS Level (OTG only) +#define MUSB_DEVCTL_VBUS_NONE 0x0000 // Below SessionEnd +#define MUSB_DEVCTL_VBUS_SEND 0x0008 // Above SessionEnd, below AValid +#define MUSB_DEVCTL_VBUS_AVALID 0x0010 // Above AValid, below VBUSValid +#define MUSB_DEVCTL_VBUS_VALID 0x0018 // Above VBUSValid +#define MUSB_DEVCTL_HOST 0x0004 // Host Mode +#define MUSB_DEVCTL_HOSTREQ 0x0002 // Host Request (OTG only) +#define MUSB_DEVCTL_SESSION 0x0001 // Session Start/End (OTG only) //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_TXTYPE5 register. +// The following are defines for the bit fields in the MUSB_O_CCONF register. // //***************************************************************************** -#define USB_TXTYPE5_SPEED_M 0x000000C0 // Operating Speed -#define USB_TXTYPE5_SPEED_DFLT 0x00000000 // Default -#define USB_TXTYPE5_SPEED_HIGH 0x00000040 // High -#define USB_TXTYPE5_SPEED_FULL 0x00000080 // Full -#define USB_TXTYPE5_SPEED_LOW 0x000000C0 // Low -#define USB_TXTYPE5_PROTO_M 0x00000030 // Protocol -#define USB_TXTYPE5_PROTO_CTRL 0x00000000 // Control -#define USB_TXTYPE5_PROTO_ISOC 0x00000010 // Isochronous -#define USB_TXTYPE5_PROTO_BULK 0x00000020 // Bulk -#define USB_TXTYPE5_PROTO_INT 0x00000030 // Interrupt -#define USB_TXTYPE5_TEP_M 0x0000000F // Target Endpoint Number -#define USB_TXTYPE5_TEP_S 0 +#define MUSB_CCONF_TXEDMA 0x0002 // TX Early DMA Enable +#define MUSB_CCONF_RXEDMA 0x0001 // TX Early DMA Enable //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_TXINTERVAL5 +// The following are defines for the bit fields in the MUSB_O_ULPIVBUSCTL // register. // //***************************************************************************** -#define USB_TXINTERVAL5_TXPOLL_M \ - 0x000000FF // TX Polling -#define USB_TXINTERVAL5_NAKLMT_M \ - 0x000000FF // NAK Limit -#define USB_TXINTERVAL5_NAKLMT_S \ - 0 -#define USB_TXINTERVAL5_TXPOLL_S \ - 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXTYPE5 register. -// -//***************************************************************************** -#define USB_RXTYPE5_SPEED_M 0x000000C0 // Operating Speed -#define USB_RXTYPE5_SPEED_DFLT 0x00000000 // Default -#define USB_RXTYPE5_SPEED_HIGH 0x00000040 // High -#define USB_RXTYPE5_SPEED_FULL 0x00000080 // Full -#define USB_RXTYPE5_SPEED_LOW 0x000000C0 // Low -#define USB_RXTYPE5_PROTO_M 0x00000030 // Protocol -#define USB_RXTYPE5_PROTO_CTRL 0x00000000 // Control -#define USB_RXTYPE5_PROTO_ISOC 0x00000010 // Isochronous -#define USB_RXTYPE5_PROTO_BULK 0x00000020 // Bulk -#define USB_RXTYPE5_PROTO_INT 0x00000030 // Interrupt -#define USB_RXTYPE5_TEP_M 0x0000000F // Target Endpoint Number -#define USB_RXTYPE5_TEP_S 0 +#define MUSB_ULPIVBUSCTL_USEEXTVBUSIND 0x0002 // Use External VBUS Indicator +#define MUSB_ULPIVBUSCTL_USEEXTVBUS 0x0001 // Use External VBUS //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_RXINTERVAL5 +// The following are defines for the bit fields in the MUSB_O_ULPIREGDATA // register. // //***************************************************************************** -#define USB_RXINTERVAL5_TXPOLL_M \ - 0x000000FF // RX Polling -#define USB_RXINTERVAL5_NAKLMT_M \ - 0x000000FF // NAK Limit -#define USB_RXINTERVAL5_TXPOLL_S \ - 0 -#define USB_RXINTERVAL5_NAKLMT_S \ - 0 - +#define MUSB_ULPIREGDATA_REGDATA_M 0x00FF // Register Data +#define MUSB_ULPIREGDATA_REGDATA_S 0 //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_TXMAXP6 register. -// -//***************************************************************************** -#define USB_TXMAXP6_MAXLOAD_M 0x000007FF // Maximum Payload -#define USB_TXMAXP6_MAXLOAD_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXCSRL6 register. -// -//***************************************************************************** -#define USB_TXCSRL6_NAKTO 0x00000080 // NAK Timeout -#define USB_TXCSRL6_CLRDT 0x00000040 // Clear Data Toggle -#define USB_TXCSRL6_STALLED 0x00000020 // Endpoint Stalled -#define USB_TXCSRL6_STALL 0x00000010 // Send STALL -#define USB_TXCSRL6_SETUP 0x00000010 // Setup Packet -#define USB_TXCSRL6_FLUSH 0x00000008 // Flush FIFO -#define USB_TXCSRL6_ERROR 0x00000004 // Error -#define USB_TXCSRL6_UNDRN 0x00000004 // Underrun -#define USB_TXCSRL6_FIFONE 0x00000002 // FIFO Not Empty -#define USB_TXCSRL6_TXRDY 0x00000001 // Transmit Packet Ready - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXCSRH6 register. -// -//***************************************************************************** -#define USB_TXCSRH6_AUTOSET 0x00000080 // Auto Set -#define USB_TXCSRH6_ISO 0x00000040 // Isochronous Transfers -#define USB_TXCSRH6_MODE 0x00000020 // Mode -#define USB_TXCSRH6_DMAEN 0x00000010 // DMA Request Enable -#define USB_TXCSRH6_FDT 0x00000008 // Force Data Toggle -#define USB_TXCSRH6_DMAMOD 0x00000004 // DMA Request Mode -#define USB_TXCSRH6_DTWE 0x00000002 // Data Toggle Write Enable -#define USB_TXCSRH6_DT 0x00000001 // Data Toggle - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXMAXP6 register. -// -//***************************************************************************** -#define USB_RXMAXP6_MAXLOAD_M 0x000007FF // Maximum Payload -#define USB_RXMAXP6_MAXLOAD_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXCSRL6 register. -// -//***************************************************************************** -#define USB_RXCSRL6_CLRDT 0x00000080 // Clear Data Toggle -#define USB_RXCSRL6_STALLED 0x00000040 // Endpoint Stalled -#define USB_RXCSRL6_REQPKT 0x00000020 // Request Packet -#define USB_RXCSRL6_STALL 0x00000020 // Send STALL -#define USB_RXCSRL6_FLUSH 0x00000010 // Flush FIFO -#define USB_RXCSRL6_NAKTO 0x00000008 // NAK Timeout -#define USB_RXCSRL6_DATAERR 0x00000008 // Data Error -#define USB_RXCSRL6_ERROR 0x00000004 // Error -#define USB_RXCSRL6_OVER 0x00000004 // Overrun -#define USB_RXCSRL6_FULL 0x00000002 // FIFO Full -#define USB_RXCSRL6_RXRDY 0x00000001 // Receive Packet Ready - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXCSRH6 register. -// -//***************************************************************************** -#define USB_RXCSRH6_AUTOCL 0x00000080 // Auto Clear -#define USB_RXCSRH6_AUTORQ 0x00000040 // Auto Request -#define USB_RXCSRH6_ISO 0x00000040 // Isochronous Transfers -#define USB_RXCSRH6_DMAEN 0x00000020 // DMA Request Enable -#define USB_RXCSRH6_DISNYET 0x00000010 // Disable NYET -#define USB_RXCSRH6_PIDERR 0x00000010 // PID Error -#define USB_RXCSRH6_DMAMOD 0x00000008 // DMA Request Mode -#define USB_RXCSRH6_DTWE 0x00000004 // Data Toggle Write Enable -#define USB_RXCSRH6_DT 0x00000002 // Data Toggle -#define USB_RXCSRH6_INCOMPRX 0x00000001 // Incomplete RX Transmission - // Status - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXCOUNT6 register. -// -//***************************************************************************** -#define USB_RXCOUNT6_COUNT_M 0x00001FFF // Receive Packet Count -#define USB_RXCOUNT6_COUNT_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXTYPE6 register. -// -//***************************************************************************** -#define USB_TXTYPE6_SPEED_M 0x000000C0 // Operating Speed -#define USB_TXTYPE6_SPEED_DFLT 0x00000000 // Default -#define USB_TXTYPE6_SPEED_HIGH 0x00000040 // High -#define USB_TXTYPE6_SPEED_FULL 0x00000080 // Full -#define USB_TXTYPE6_SPEED_LOW 0x000000C0 // Low -#define USB_TXTYPE6_PROTO_M 0x00000030 // Protocol -#define USB_TXTYPE6_PROTO_CTRL 0x00000000 // Control -#define USB_TXTYPE6_PROTO_ISOC 0x00000010 // Isochronous -#define USB_TXTYPE6_PROTO_BULK 0x00000020 // Bulk -#define USB_TXTYPE6_PROTO_INT 0x00000030 // Interrupt -#define USB_TXTYPE6_TEP_M 0x0000000F // Target Endpoint Number -#define USB_TXTYPE6_TEP_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_TXINTERVAL6 +// The following are defines for the bit fields in the MUSB_O_ULPIREGADDR // register. // //***************************************************************************** -#define USB_TXINTERVAL6_TXPOLL_M \ - 0x000000FF // TX Polling -#define USB_TXINTERVAL6_NAKLMT_M \ - 0x000000FF // NAK Limit -#define USB_TXINTERVAL6_TXPOLL_S \ - 0 -#define USB_TXINTERVAL6_NAKLMT_S \ - 0 +#define MUSB_ULPIREGADDR_ADDR_M 0x00FF // Register Address +#define MUSB_ULPIREGADDR_ADDR_S 0 //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_RXTYPE6 register. -// -//***************************************************************************** -#define USB_RXTYPE6_SPEED_M 0x000000C0 // Operating Speed -#define USB_RXTYPE6_SPEED_DFLT 0x00000000 // Default -#define USB_RXTYPE6_SPEED_HIGH 0x00000040 // High -#define USB_RXTYPE6_SPEED_FULL 0x00000080 // Full -#define USB_RXTYPE6_SPEED_LOW 0x000000C0 // Low -#define USB_RXTYPE6_PROTO_M 0x00000030 // Protocol -#define USB_RXTYPE6_PROTO_CTRL 0x00000000 // Control -#define USB_RXTYPE6_PROTO_ISOC 0x00000010 // Isochronous -#define USB_RXTYPE6_PROTO_BULK 0x00000020 // Bulk -#define USB_RXTYPE6_PROTO_INT 0x00000030 // Interrupt -#define USB_RXTYPE6_TEP_M 0x0000000F // Target Endpoint Number -#define USB_RXTYPE6_TEP_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RXINTERVAL6 +// The following are defines for the bit fields in the MUSB_O_ULPIREGCTL // register. // //***************************************************************************** -#define USB_RXINTERVAL6_TXPOLL_M \ - 0x000000FF // RX Polling -#define USB_RXINTERVAL6_NAKLMT_M \ - 0x000000FF // NAK Limit -#define USB_RXINTERVAL6_NAKLMT_S \ - 0 -#define USB_RXINTERVAL6_TXPOLL_S \ - 0 +#define MUSB_ULPIREGCTL_RDWR 0x0004 // Read/Write Control +#define MUSB_ULPIREGCTL_REGCMPLT 0x0002 // Register Access Complete +#define MUSB_ULPIREGCTL_REGACC 0x0001 // Initiate Register Access //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_TXMAXP7 register. +// The following are defines for the bit fields in the MUSB_O_EPINFO register. // //***************************************************************************** -#define USB_TXMAXP7_MAXLOAD_M 0x000007FF // Maximum Payload -#define USB_TXMAXP7_MAXLOAD_S 0 +#define MUSB_EPINFO_RXEP_M 0x00F0 // RX Endpoints +#define MUSB_EPINFO_TXEP_M 0x000F // TX Endpoints +#define MUSB_EPINFO_RXEP_S 4 +#define MUSB_EPINFO_TXEP_S 0 //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_TXCSRL7 register. +// The following are defines for the bit fields in the MUSB_O_RAMINFO register. // //***************************************************************************** -#define USB_TXCSRL7_NAKTO 0x00000080 // NAK Timeout -#define USB_TXCSRL7_CLRDT 0x00000040 // Clear Data Toggle -#define USB_TXCSRL7_STALLED 0x00000020 // Endpoint Stalled -#define USB_TXCSRL7_STALL 0x00000010 // Send STALL -#define USB_TXCSRL7_SETUP 0x00000010 // Setup Packet -#define USB_TXCSRL7_FLUSH 0x00000008 // Flush FIFO -#define USB_TXCSRL7_ERROR 0x00000004 // Error -#define USB_TXCSRL7_UNDRN 0x00000004 // Underrun -#define USB_TXCSRL7_FIFONE 0x00000002 // FIFO Not Empty -#define USB_TXCSRL7_TXRDY 0x00000001 // Transmit Packet Ready +#define MUSB_RAMINFO_DMACHAN_M 0x00F0 // DMA Channels +#define MUSB_RAMINFO_RAMBITS_M 0x000F // RAM Address Bus Width +#define MUSB_RAMINFO_DMACHAN_S 4 +#define MUSB_RAMINFO_RAMBITS_S 0 //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_TXCSRH7 register. +// The following are defines for the bit fields in the MUSB_O_CONTIM register. // //***************************************************************************** -#define USB_TXCSRH7_AUTOSET 0x00000080 // Auto Set -#define USB_TXCSRH7_ISO 0x00000040 // Isochronous Transfers -#define USB_TXCSRH7_MODE 0x00000020 // Mode -#define USB_TXCSRH7_DMAEN 0x00000010 // DMA Request Enable -#define USB_TXCSRH7_FDT 0x00000008 // Force Data Toggle -#define USB_TXCSRH7_DMAMOD 0x00000004 // DMA Request Mode -#define USB_TXCSRH7_DTWE 0x00000002 // Data Toggle Write Enable -#define USB_TXCSRH7_DT 0x00000001 // Data Toggle +#define MUSB_CONTIM_WTCON_M 0x00F0 // Connect Wait +#define MUSB_CONTIM_WTID_M 0x000F // Wait ID +#define MUSB_CONTIM_WTCON_S 4 +#define MUSB_CONTIM_WTID_S 0 //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_RXMAXP7 register. +// The following are defines for the bit fields in the MUSB_O_VPLEN register. // //***************************************************************************** -#define USB_RXMAXP7_MAXLOAD_M 0x000007FF // Maximum Payload -#define USB_RXMAXP7_MAXLOAD_S 0 +#define MUSB_VPLEN_VPLEN_M 0x00FF // VBUS Pulse Length +#define MUSB_VPLEN_VPLEN_S 0 //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_RXCSRL7 register. +// The following are defines for the bit fields in the MUSB_O_HSEOF register. // //***************************************************************************** -#define USB_RXCSRL7_CLRDT 0x00000080 // Clear Data Toggle -#define USB_RXCSRL7_STALLED 0x00000040 // Endpoint Stalled -#define USB_RXCSRL7_REQPKT 0x00000020 // Request Packet -#define USB_RXCSRL7_STALL 0x00000020 // Send STALL -#define USB_RXCSRL7_FLUSH 0x00000010 // Flush FIFO -#define USB_RXCSRL7_DATAERR 0x00000008 // Data Error -#define USB_RXCSRL7_NAKTO 0x00000008 // NAK Timeout -#define USB_RXCSRL7_ERROR 0x00000004 // Error -#define USB_RXCSRL7_OVER 0x00000004 // Overrun -#define USB_RXCSRL7_FULL 0x00000002 // FIFO Full -#define USB_RXCSRL7_RXRDY 0x00000001 // Receive Packet Ready +#define MUSB_HSEOF_HSEOFG_M 0x00FF // HIgh-Speed End-of-Frame Gap +#define MUSB_HSEOF_HSEOFG_S 0 //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_RXCSRH7 register. +// The following are defines for the bit fields in the MUSB_O_FSEOF register. // //***************************************************************************** -#define USB_RXCSRH7_AUTOCL 0x00000080 // Auto Clear -#define USB_RXCSRH7_ISO 0x00000040 // Isochronous Transfers -#define USB_RXCSRH7_AUTORQ 0x00000040 // Auto Request -#define USB_RXCSRH7_DMAEN 0x00000020 // DMA Request Enable -#define USB_RXCSRH7_PIDERR 0x00000010 // PID Error -#define USB_RXCSRH7_DISNYET 0x00000010 // Disable NYET -#define USB_RXCSRH7_DMAMOD 0x00000008 // DMA Request Mode -#define USB_RXCSRH7_DTWE 0x00000004 // Data Toggle Write Enable -#define USB_RXCSRH7_DT 0x00000002 // Data Toggle -#define USB_RXCSRH7_INCOMPRX 0x00000001 // Incomplete RX Transmission - // Status +#define MUSB_FSEOF_FSEOFG_M 0x00FF // Full-Speed End-of-Frame Gap +#define MUSB_FSEOF_FSEOFG_S 0 //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_RXCOUNT7 register. +// The following are defines for the bit fields in the MUSB_O_LSEOF register. // //***************************************************************************** -#define USB_RXCOUNT7_COUNT_M 0x00001FFF // Receive Packet Count -#define USB_RXCOUNT7_COUNT_S 0 +#define MUSB_LSEOF_LSEOFG_M 0x00FF // Low-Speed End-of-Frame Gap +#define MUSB_LSEOF_LSEOFG_S 0 //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_TXTYPE7 register. +// The following are defines for the bit fields in the MUSB_O_CSRL0 register. // //***************************************************************************** -#define USB_TXTYPE7_SPEED_M 0x000000C0 // Operating Speed -#define USB_TXTYPE7_SPEED_DFLT 0x00000000 // Default -#define USB_TXTYPE7_SPEED_HIGH 0x00000040 // High -#define USB_TXTYPE7_SPEED_FULL 0x00000080 // Full -#define USB_TXTYPE7_SPEED_LOW 0x000000C0 // Low -#define USB_TXTYPE7_PROTO_M 0x00000030 // Protocol -#define USB_TXTYPE7_PROTO_CTRL 0x00000000 // Control -#define USB_TXTYPE7_PROTO_ISOC 0x00000010 // Isochronous -#define USB_TXTYPE7_PROTO_BULK 0x00000020 // Bulk -#define USB_TXTYPE7_PROTO_INT 0x00000030 // Interrupt -#define USB_TXTYPE7_TEP_M 0x0000000F // Target Endpoint Number -#define USB_TXTYPE7_TEP_S 0 +#define MUSB_CSRL0_NAKTO 0x0080 // NAK Timeout +#define MUSB_CSRL0_SETENDC 0x0080 // Setup End Clear +#define MUSB_CSRL0_STATUS 0x0040 // STATUS Packet +#define MUSB_CSRL0_RXRDYC 0x0040 // RXRDY Clear +#define MUSB_CSRL0_REQPKT 0x0020 // Request Packet +#define MUSB_CSRL0_STALL 0x0020 // Send Stall +#define MUSB_CSRL0_SETEND 0x0010 // Setup End +#define MUSB_CSRL0_ERROR 0x0010 // Error +#define MUSB_CSRL0_DATAEND 0x0008 // Data End +#define MUSB_CSRL0_SETUP 0x0008 // Setup Packet +#define MUSB_CSRL0_STALLED 0x0004 // Endpoint Stalled +#define MUSB_CSRL0_TXRDY 0x0002 // Transmit Packet Ready +#define MUSB_CSRL0_RXRDY 0x0001 // Receive Packet Ready //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_TXINTERVAL7 -// register. +// The following are defines for the bit fields in the MUSB_O_CSRH0 register. // //***************************************************************************** -#define USB_TXINTERVAL7_TXPOLL_M \ - 0x000000FF // TX Polling -#define USB_TXINTERVAL7_NAKLMT_M \ - 0x000000FF // NAK Limit -#define USB_TXINTERVAL7_NAKLMT_S \ - 0 -#define USB_TXINTERVAL7_TXPOLL_S \ - 0 +#define MUSB_CSRH0_DISPING 0x0008 // PING Disable +#define MUSB_CSRH0_DTWE 0x0004 // Data Toggle Write Enable +#define MUSB_CSRH0_DT 0x0002 // Data Toggle +#define MUSB_CSRH0_FLUSH 0x0001 // Flush FIFO //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_RXTYPE7 register. +// The following are defines for the bit fields in the MUSB_O_TYPE0 register. // //***************************************************************************** -#define USB_RXTYPE7_SPEED_M 0x000000C0 // Operating Speed -#define USB_RXTYPE7_SPEED_DFLT 0x00000000 // Default -#define USB_RXTYPE7_SPEED_HIGH 0x00000040 // High -#define USB_RXTYPE7_SPEED_FULL 0x00000080 // Full -#define USB_RXTYPE7_SPEED_LOW 0x000000C0 // Low -#define USB_RXTYPE7_PROTO_M 0x00000030 // Protocol -#define USB_RXTYPE7_PROTO_CTRL 0x00000000 // Control -#define USB_RXTYPE7_PROTO_ISOC 0x00000010 // Isochronous -#define USB_RXTYPE7_PROTO_BULK 0x00000020 // Bulk -#define USB_RXTYPE7_PROTO_INT 0x00000030 // Interrupt -#define USB_RXTYPE7_TEP_M 0x0000000F // Target Endpoint Number -#define USB_RXTYPE7_TEP_S 0 +#define MUSB_TYPE0_SPEED_M 0x00C0 // Operating Speed +#define MUSB_TYPE0_SPEED_HIGH 0x0040 // High +#define MUSB_TYPE0_SPEED_FULL 0x0080 // Full +#define MUSB_TYPE0_SPEED_LOW 0x00C0 // Low //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_RXINTERVAL7 -// register. -// -//***************************************************************************** -#define USB_RXINTERVAL7_TXPOLL_M \ - 0x000000FF // RX Polling -#define USB_RXINTERVAL7_NAKLMT_M \ - 0x000000FF // NAK Limit -#define USB_RXINTERVAL7_NAKLMT_S \ - 0 -#define USB_RXINTERVAL7_TXPOLL_S \ - 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_DMAINTR register. -// -//***************************************************************************** -#define USB_DMAINTR_CH7 0x00000080 // Channel 7 DMA Interrupt -#define USB_DMAINTR_CH6 0x00000040 // Channel 6 DMA Interrupt -#define USB_DMAINTR_CH5 0x00000020 // Channel 5 DMA Interrupt -#define USB_DMAINTR_CH4 0x00000010 // Channel 4 DMA Interrupt -#define USB_DMAINTR_CH3 0x00000008 // Channel 3 DMA Interrupt -#define USB_DMAINTR_CH2 0x00000004 // Channel 2 DMA Interrupt -#define USB_DMAINTR_CH1 0x00000002 // Channel 1 DMA Interrupt -#define USB_DMAINTR_CH0 0x00000001 // Channel 0 DMA Interrupt - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_DMACTL0 register. -// -//***************************************************************************** -#define USB_DMACTL0_BRSTM_M 0x00000600 // Burst Mode -#define USB_DMACTL0_BRSTM_ANY 0x00000000 // Bursts of unspecified length -#define USB_DMACTL0_BRSTM_INC4 0x00000200 // INCR4 or unspecified length -#define USB_DMACTL0_BRSTM_INC8 0x00000400 // INCR8, INCR4 or unspecified - // length -#define USB_DMACTL0_BRSTM_INC16 0x00000600 // INCR16, INCR8, INCR4 or - // unspecified length -#define USB_DMACTL0_ERR 0x00000100 // Bus Error Bit -#define USB_DMACTL0_EP_M 0x000000F0 // Endpoint number -#define USB_DMACTL0_IE 0x00000008 // DMA Interrupt Enable -#define USB_DMACTL0_MODE 0x00000004 // DMA Transfer Mode -#define USB_DMACTL0_DIR 0x00000002 // DMA Direction -#define USB_DMACTL0_ENABLE 0x00000001 // DMA Transfer Enable -#define USB_DMACTL0_EP_S 4 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_DMAADDR0 register. -// -//***************************************************************************** -#define USB_DMAADDR0_ADDR_M 0xFFFFFFFC // DMA Address -#define USB_DMAADDR0_ADDR_S 2 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_DMACOUNT0 -// register. -// -//***************************************************************************** -#define USB_DMACOUNT0_COUNT_M 0xFFFFFFFC // DMA Count -#define USB_DMACOUNT0_COUNT_S 2 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_DMACTL1 register. -// -//***************************************************************************** -#define USB_DMACTL1_BRSTM_M 0x00000600 // Burst Mode -#define USB_DMACTL1_BRSTM_ANY 0x00000000 // Bursts of unspecified length -#define USB_DMACTL1_BRSTM_INC4 0x00000200 // INCR4 or unspecified length -#define USB_DMACTL1_BRSTM_INC8 0x00000400 // INCR8, INCR4 or unspecified - // length -#define USB_DMACTL1_BRSTM_INC16 0x00000600 // INCR16, INCR8, INCR4 or - // unspecified length -#define USB_DMACTL1_ERR 0x00000100 // Bus Error Bit -#define USB_DMACTL1_EP_M 0x000000F0 // Endpoint number -#define USB_DMACTL1_IE 0x00000008 // DMA Interrupt Enable -#define USB_DMACTL1_MODE 0x00000004 // DMA Transfer Mode -#define USB_DMACTL1_DIR 0x00000002 // DMA Direction -#define USB_DMACTL1_ENABLE 0x00000001 // DMA Transfer Enable -#define USB_DMACTL1_EP_S 4 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_DMAADDR1 register. -// -//***************************************************************************** -#define USB_DMAADDR1_ADDR_M 0xFFFFFFFC // DMA Address -#define USB_DMAADDR1_ADDR_S 2 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_DMACOUNT1 -// register. -// -//***************************************************************************** -#define USB_DMACOUNT1_COUNT_M 0xFFFFFFFC // DMA Count -#define USB_DMACOUNT1_COUNT_S 2 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_DMACTL2 register. -// -//***************************************************************************** -#define USB_DMACTL2_BRSTM_M 0x00000600 // Burst Mode -#define USB_DMACTL2_BRSTM_ANY 0x00000000 // Bursts of unspecified length -#define USB_DMACTL2_BRSTM_INC4 0x00000200 // INCR4 or unspecified length -#define USB_DMACTL2_BRSTM_INC8 0x00000400 // INCR8, INCR4 or unspecified - // length -#define USB_DMACTL2_BRSTM_INC16 0x00000600 // INCR16, INCR8, INCR4 or - // unspecified length -#define USB_DMACTL2_ERR 0x00000100 // Bus Error Bit -#define USB_DMACTL2_EP_M 0x000000F0 // Endpoint number -#define USB_DMACTL2_IE 0x00000008 // DMA Interrupt Enable -#define USB_DMACTL2_MODE 0x00000004 // DMA Transfer Mode -#define USB_DMACTL2_DIR 0x00000002 // DMA Direction -#define USB_DMACTL2_ENABLE 0x00000001 // DMA Transfer Enable -#define USB_DMACTL2_EP_S 4 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_DMAADDR2 register. -// -//***************************************************************************** -#define USB_DMAADDR2_ADDR_M 0xFFFFFFFC // DMA Address -#define USB_DMAADDR2_ADDR_S 2 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_DMACOUNT2 -// register. -// -//***************************************************************************** -#define USB_DMACOUNT2_COUNT_M 0xFFFFFFFC // DMA Count -#define USB_DMACOUNT2_COUNT_S 2 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_DMACTL3 register. +// The following are defines for the bit fields in the MUSB_O_NAKLMT register. // //***************************************************************************** -#define USB_DMACTL3_BRSTM_M 0x00000600 // Burst Mode -#define USB_DMACTL3_BRSTM_ANY 0x00000000 // Bursts of unspecified length -#define USB_DMACTL3_BRSTM_INC4 0x00000200 // INCR4 or unspecified length -#define USB_DMACTL3_BRSTM_INC8 0x00000400 // INCR8, INCR4 or unspecified - // length -#define USB_DMACTL3_BRSTM_INC16 0x00000600 // INCR16, INCR8, INCR4 or - // unspecified length -#define USB_DMACTL3_ERR 0x00000100 // Bus Error Bit -#define USB_DMACTL3_EP_M 0x000000F0 // Endpoint number -#define USB_DMACTL3_IE 0x00000008 // DMA Interrupt Enable -#define USB_DMACTL3_MODE 0x00000004 // DMA Transfer Mode -#define USB_DMACTL3_DIR 0x00000002 // DMA Direction -#define USB_DMACTL3_ENABLE 0x00000001 // DMA Transfer Enable -#define USB_DMACTL3_EP_S 4 +#define MUSB_NAKLMT_NAKLMT_M 0x001F // EP0 NAK Limit +#define MUSB_NAKLMT_NAKLMT_S 0 //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_DMAADDR3 register. +// The following are defines for the bit fields in the MUSB_O_TXCSRL1 register. // //***************************************************************************** -#define USB_DMAADDR3_ADDR_M 0xFFFFFFFC // DMA Address -#define USB_DMAADDR3_ADDR_S 2 +#define MUSB_TXCSRL1_NAKTO 0x0080 // NAK Timeout +#define MUSB_TXCSRL1_CLRDT 0x0040 // Clear Data Toggle +#define MUSB_TXCSRL1_STALLED 0x0020 // Endpoint Stalled +#define MUSB_TXCSRL1_STALL 0x0010 // Send STALL +#define MUSB_TXCSRL1_SETUP 0x0010 // Setup Packet +#define MUSB_TXCSRL1_FLUSH 0x0008 // Flush FIFO +#define MUSB_TXCSRL1_ERROR 0x0004 // Error +#define MUSB_TXCSRL1_UNDRN 0x0004 // Underrun +#define MUSB_TXCSRL1_FIFONE 0x0002 // FIFO Not Empty +#define MUSB_TXCSRL1_TXRDY 0x0001 // Transmit Packet Ready //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_DMACOUNT3 -// register. +// The following are defines for the bit fields in the MUSB_O_TXCSRH1 register. // //***************************************************************************** -#define USB_DMACOUNT3_COUNT_M 0xFFFFFFFC // DMA Count -#define USB_DMACOUNT3_COUNT_S 2 +#define MUSB_TXCSRH1_AUTOSET 0x0080 // Auto Set +#define MUSB_TXCSRH1_ISO 0x0040 // Isochronous Transfers +#define MUSB_TXCSRH1_MODE 0x0020 // Mode +#define MUSB_TXCSRH1_DMAEN 0x0010 // DMA Request Enable +#define MUSB_TXCSRH1_FDT 0x0008 // Force Data Toggle +#define MUSB_TXCSRH1_DMAMOD 0x0004 // DMA Request Mode +#define MUSB_TXCSRH1_DTWE 0x0002 // Data Toggle Write Enable +#define MUSB_TXCSRH1_DT 0x0001 // Data Toggle //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_DMACTL4 register. +// The following are defines for the bit fields in the MUSB_O_RXCSRL1 register. // //***************************************************************************** -#define USB_DMACTL4_BRSTM_M 0x00000600 // Burst Mode -#define USB_DMACTL4_BRSTM_ANY 0x00000000 // Bursts of unspecified length -#define USB_DMACTL4_BRSTM_INC4 0x00000200 // INCR4 or unspecified length -#define USB_DMACTL4_BRSTM_INC8 0x00000400 // INCR8, INCR4 or unspecified - // length -#define USB_DMACTL4_BRSTM_INC16 0x00000600 // INCR16, INCR8, INCR4 or - // unspecified length -#define USB_DMACTL4_ERR 0x00000100 // Bus Error Bit -#define USB_DMACTL4_EP_M 0x000000F0 // Endpoint number -#define USB_DMACTL4_IE 0x00000008 // DMA Interrupt Enable -#define USB_DMACTL4_MODE 0x00000004 // DMA Transfer Mode -#define USB_DMACTL4_DIR 0x00000002 // DMA Direction -#define USB_DMACTL4_ENABLE 0x00000001 // DMA Transfer Enable -#define USB_DMACTL4_EP_S 4 +#define MUSB_RXCSRL1_CLRDT 0x0080 // Clear Data Toggle +#define MUSB_RXCSRL1_STALLED 0x0040 // Endpoint Stalled +#define MUSB_RXCSRL1_STALL 0x0020 // Send STALL +#define MUSB_RXCSRL1_REQPKT 0x0020 // Request Packet +#define MUSB_RXCSRL1_FLUSH 0x0010 // Flush FIFO +#define MUSB_RXCSRL1_DATAERR 0x0008 // Data Error +#define MUSB_RXCSRL1_NAKTO 0x0008 // NAK Timeout +#define MUSB_RXCSRL1_OVER 0x0004 // Overrun +#define MUSB_RXCSRL1_ERROR 0x0004 // Error +#define MUSB_RXCSRL1_FULL 0x0002 // FIFO Full +#define MUSB_RXCSRL1_RXRDY 0x0001 // Receive Packet Ready //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_DMAADDR4 register. +// The following are defines for the bit fields in the MUSB_O_RXCSRH1 register. // //***************************************************************************** -#define USB_DMAADDR4_ADDR_M 0xFFFFFFFC // DMA Address -#define USB_DMAADDR4_ADDR_S 2 +#define MUSB_RXCSRH1_AUTOCL 0x0080 // Auto Clear +#define MUSB_RXCSRH1_AUTORQ 0x0040 // Auto Request +#define MUSB_RXCSRH1_ISO 0x0040 // Isochronous Transfers +#define MUSB_RXCSRH1_DMAEN 0x0020 // DMA Request Enable +#define MUSB_RXCSRH1_DISNYET 0x0010 // Disable NYET +#define MUSB_RXCSRH1_PIDERR 0x0010 // PID Error +#define MUSB_RXCSRH1_DMAMOD 0x0008 // DMA Request Mode +#define MUSB_RXCSRH1_DTWE 0x0004 // Data Toggle Write Enable +#define MUSB_RXCSRH1_DT 0x0002 // Data Toggle +#define MUSB_RXCSRH1_INCOMPRX 0x0001 // Incomplete RX Transmission Status //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_DMACOUNT4 -// register. +// The following are defines for the bit fields in the MUSB_O_TXTYPE1 register. // //***************************************************************************** -#define USB_DMACOUNT4_COUNT_M 0xFFFFFFFC // DMA Count -#define USB_DMACOUNT4_COUNT_S 2 +#define MUSB_TXTYPE1_SPEED_M 0x00C0 // Operating Speed +#define MUSB_TXTYPE1_SPEED_DFLT 0x0000 // Default +#define MUSB_TXTYPE1_SPEED_HIGH 0x0040 // High +#define MUSB_TXTYPE1_SPEED_FULL 0x0080 // Full +#define MUSB_TXTYPE1_SPEED_LOW 0x00C0 // Low +#define MUSB_TXTYPE1_PROTO_M 0x0030 // Protocol +#define MUSB_TXTYPE1_PROTO_CTRL 0x0000 // Control +#define MUSB_TXTYPE1_PROTO_ISOC 0x0010 // Isochronous +#define MUSB_TXTYPE1_PROTO_BULK 0x0020 // Bulk +#define MUSB_TXTYPE1_PROTO_INT 0x0030 // Interrupt +#define MUSB_TXTYPE1_TEP_M 0x000F // Target Endpoint Number +#define MUSB_TXTYPE1_TEP_S 0 //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_DMACTL5 register. -// -//***************************************************************************** -#define USB_DMACTL5_BRSTM_M 0x00000600 // Burst Mode -#define USB_DMACTL5_BRSTM_ANY 0x00000000 // Bursts of unspecified length -#define USB_DMACTL5_BRSTM_INC4 0x00000200 // INCR4 or unspecified length -#define USB_DMACTL5_BRSTM_INC8 0x00000400 // INCR8, INCR4 or unspecified - // length -#define USB_DMACTL5_BRSTM_INC16 0x00000600 // INCR16, INCR8, INCR4 or - // unspecified length -#define USB_DMACTL5_ERR 0x00000100 // Bus Error Bit -#define USB_DMACTL5_EP_M 0x000000F0 // Endpoint number -#define USB_DMACTL5_IE 0x00000008 // DMA Interrupt Enable -#define USB_DMACTL5_MODE 0x00000004 // DMA Transfer Mode -#define USB_DMACTL5_DIR 0x00000002 // DMA Direction -#define USB_DMACTL5_ENABLE 0x00000001 // DMA Transfer Enable -#define USB_DMACTL5_EP_S 4 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_DMAADDR5 register. -// -//***************************************************************************** -#define USB_DMAADDR5_ADDR_M 0xFFFFFFFC // DMA Address -#define USB_DMAADDR5_ADDR_S 2 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_DMACOUNT5 +// The following are defines for the bit fields in the MUSB_O_TXINTERVAL1 // register. // //***************************************************************************** -#define USB_DMACOUNT5_COUNT_M 0xFFFFFFFC // DMA Count -#define USB_DMACOUNT5_COUNT_S 2 +#define MUSB_TXINTERVAL1_NAKLMT_M 0x00FF // NAK Limit +#define MUSB_TXINTERVAL1_TXPOLL_M 0x00FF // TX Polling +#define MUSB_TXINTERVAL1_TXPOLL_S 0 +#define MUSB_TXINTERVAL1_NAKLMT_S 0 //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_DMACTL6 register. +// The following are defines for the bit fields in the MUSB_O_RXTYPE1 register. // //***************************************************************************** -#define USB_DMACTL6_BRSTM_M 0x00000600 // Burst Mode -#define USB_DMACTL6_BRSTM_ANY 0x00000000 // Bursts of unspecified length -#define USB_DMACTL6_BRSTM_INC4 0x00000200 // INCR4 or unspecified length -#define USB_DMACTL6_BRSTM_INC8 0x00000400 // INCR8, INCR4 or unspecified - // length -#define USB_DMACTL6_BRSTM_INC16 0x00000600 // INCR16, INCR8, INCR4 or - // unspecified length -#define USB_DMACTL6_ERR 0x00000100 // Bus Error Bit -#define USB_DMACTL6_EP_M 0x000000F0 // Endpoint number -#define USB_DMACTL6_IE 0x00000008 // DMA Interrupt Enable -#define USB_DMACTL6_MODE 0x00000004 // DMA Transfer Mode -#define USB_DMACTL6_DIR 0x00000002 // DMA Direction -#define USB_DMACTL6_ENABLE 0x00000001 // DMA Transfer Enable -#define USB_DMACTL6_EP_S 4 +#define MUSB_RXTYPE1_SPEED_M 0x00C0 // Operating Speed +#define MUSB_RXTYPE1_SPEED_DFLT 0x0000 // Default +#define MUSB_RXTYPE1_SPEED_HIGH 0x0040 // High +#define MUSB_RXTYPE1_SPEED_FULL 0x0080 // Full +#define MUSB_RXTYPE1_SPEED_LOW 0x00C0 // Low +#define MUSB_RXTYPE1_PROTO_M 0x0030 // Protocol +#define MUSB_RXTYPE1_PROTO_CTRL 0x0000 // Control +#define MUSB_RXTYPE1_PROTO_ISOC 0x0010 // Isochronous +#define MUSB_RXTYPE1_PROTO_BULK 0x0020 // Bulk +#define MUSB_RXTYPE1_PROTO_INT 0x0030 // Interrupt +#define MUSB_RXTYPE1_TEP_M 0x000F // Target Endpoint Number +#define MUSB_RXTYPE1_TEP_S 0 //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_DMAADDR6 register. -// -//***************************************************************************** -#define USB_DMAADDR6_ADDR_M 0xFFFFFFFC // DMA Address -#define USB_DMAADDR6_ADDR_S 2 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_DMACOUNT6 +// The following are defines for the bit fields in the MUSB_O_RXINTERVAL1 // register. // //***************************************************************************** -#define USB_DMACOUNT6_COUNT_M 0xFFFFFFFC // DMA Count -#define USB_DMACOUNT6_COUNT_S 2 +#define MUSB_RXINTERVAL1_TXPOLL_M 0x00FF // RX Polling +#define MUSB_RXINTERVAL1_NAKLMT_M 0x00FF // NAK Limit +#define MUSB_RXINTERVAL1_TXPOLL_S 0 +#define MUSB_RXINTERVAL1_NAKLMT_S 0 //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_DMACTL7 register. +// The following are defines for the bit fields in the MUSB_O_DMACTL0 register. // //***************************************************************************** -#define USB_DMACTL7_BRSTM_M 0x00000600 // Burst Mode -#define USB_DMACTL7_BRSTM_ANY 0x00000000 // Bursts of unspecified length -#define USB_DMACTL7_BRSTM_INC4 0x00000200 // INCR4 or unspecified length -#define USB_DMACTL7_BRSTM_INC8 0x00000400 // INCR8, INCR4 or unspecified +#define MUSB_DMACTL0_BRSTM_M 0x0600 // Burst Mode +#define MUSB_DMACTL0_BRSTM_ANY 0x0000 // Bursts of unspecified length +#define MUSB_DMACTL0_BRSTM_INC4 0x0200 // INCR4 or unspecified length +#define MUSB_DMACTL0_BRSTM_INC8 0x0400 // INCR8, INCR4 or unspecified // length -#define USB_DMACTL7_BRSTM_INC16 0x00000600 // INCR16, INCR8, INCR4 or +#define MUSB_DMACTL0_BRSTM_INC16 0x0600 // INCR16, INCR8, INCR4 or // unspecified length -#define USB_DMACTL7_ERR 0x00000100 // Bus Error Bit -#define USB_DMACTL7_EP_M 0x000000F0 // Endpoint number -#define USB_DMACTL7_IE 0x00000008 // DMA Interrupt Enable -#define USB_DMACTL7_MODE 0x00000004 // DMA Transfer Mode -#define USB_DMACTL7_DIR 0x00000002 // DMA Direction -#define USB_DMACTL7_ENABLE 0x00000001 // DMA Transfer Enable -#define USB_DMACTL7_EP_S 4 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_DMAADDR7 register. -// -//***************************************************************************** -#define USB_DMAADDR7_ADDR_M 0xFFFFFFFC // DMA Address -#define USB_DMAADDR7_ADDR_S 2 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_DMACOUNT7 -// register. -// -//***************************************************************************** -#define USB_DMACOUNT7_COUNT_M 0xFFFFFFFC // DMA Count -#define USB_DMACOUNT7_COUNT_S 2 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RQPKTCOUNT1 -// register. -// -//***************************************************************************** -#define USB_RQPKTCOUNT1_M 0x0000FFFF // Block Transfer Packet Count -#define USB_RQPKTCOUNT1_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RQPKTCOUNT2 -// register. -// -//***************************************************************************** -#define USB_RQPKTCOUNT2_M 0x0000FFFF // Block Transfer Packet Count -#define USB_RQPKTCOUNT2_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RQPKTCOUNT3 -// register. -// -//***************************************************************************** -#define USB_RQPKTCOUNT3_M 0x0000FFFF // Block Transfer Packet Count -#define USB_RQPKTCOUNT3_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RQPKTCOUNT4 -// register. -// -//***************************************************************************** -#define USB_RQPKTCOUNT4_COUNT_M 0x0000FFFF // Block Transfer Packet Count -#define USB_RQPKTCOUNT4_COUNT_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_RQPKTCOUNT5 -// register. -// -//***************************************************************************** -#define USB_RQPKTCOUNT5_COUNT_M 0x0000FFFF // Block Transfer Packet Count -#define USB_RQPKTCOUNT5_COUNT_S 0 +#define MUSB_DMACTL0_ERR 0x0100 // Bus Error Bit +#define MUSB_DMACTL0_EP_M 0x00F0 // Endpoint number +#define MUSB_DMACTL0_IE 0x0008 // DMA Interrupt Enable +#define MUSB_DMACTL0_MODE 0x0004 // DMA Transfer Mode +#define MUSB_DMACTL0_DIR 0x0002 // DMA Direction +#define MUSB_DMACTL0_ENABLE 0x0001 // DMA Transfer Enable +#define MUSB_DMACTL0_EP_S 4 //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_RQPKTCOUNT6 -// register. +// The following are defines for the bit fields in the MUSB_O_DMAADDR0 register. // //***************************************************************************** -#define USB_RQPKTCOUNT6_COUNT_M 0x0000FFFF // Block Transfer Packet Count -#define USB_RQPKTCOUNT6_COUNT_S 0 +#define MUSB_DMAADDR0_ADDR_M 0xFFFFFFFC // DMA Address +#define MUSB_DMAADDR0_ADDR_S 2 //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_RQPKTCOUNT7 +// The following are defines for the bit fields in the MUSB_O_DMACOUNT0 // register. // //***************************************************************************** -#define USB_RQPKTCOUNT7_COUNT_M 0x0000FFFF // Block Transfer Packet Count -#define USB_RQPKTCOUNT7_COUNT_S 0 +#define MUSB_DMACOUNT0_COUNT_M 0xFFFFFFFC // DMA Count +#define MUSB_DMACOUNT0_COUNT_S 2 //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_RXDPKTBUFDIS -// register. +// The following are defines for the bit fields in the MUSB_O_CTO register. // //***************************************************************************** -#define USB_RXDPKTBUFDIS_EP7 0x00000080 // EP7 RX Double-Packet Buffer - // Disable -#define USB_RXDPKTBUFDIS_EP6 0x00000040 // EP6 RX Double-Packet Buffer - // Disable -#define USB_RXDPKTBUFDIS_EP5 0x00000020 // EP5 RX Double-Packet Buffer - // Disable -#define USB_RXDPKTBUFDIS_EP4 0x00000010 // EP4 RX Double-Packet Buffer - // Disable -#define USB_RXDPKTBUFDIS_EP3 0x00000008 // EP3 RX Double-Packet Buffer - // Disable -#define USB_RXDPKTBUFDIS_EP2 0x00000004 // EP2 RX Double-Packet Buffer - // Disable -#define USB_RXDPKTBUFDIS_EP1 0x00000002 // EP1 RX Double-Packet Buffer - // Disable +#define MUSB_CTO_CCTV_M 0xFFFF // Configurable Chirp Timeout Value +#define MUSB_CTO_CCTV_S 0 //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_TXDPKTBUFDIS -// register. +// The following are defines for the bit fields in the MUSB_O_HHSRTN register. // //***************************************************************************** -#define USB_TXDPKTBUFDIS_EP7 0x00000080 // EP7 TX Double-Packet Buffer - // Disable -#define USB_TXDPKTBUFDIS_EP6 0x00000040 // EP6 TX Double-Packet Buffer - // Disable -#define USB_TXDPKTBUFDIS_EP5 0x00000020 // EP5 TX Double-Packet Buffer - // Disable -#define USB_TXDPKTBUFDIS_EP4 0x00000010 // EP4 TX Double-Packet Buffer - // Disable -#define USB_TXDPKTBUFDIS_EP3 0x00000008 // EP3 TX Double-Packet Buffer - // Disable -#define USB_TXDPKTBUFDIS_EP2 0x00000004 // EP2 TX Double-Packet Buffer - // Disable -#define USB_TXDPKTBUFDIS_EP1 0x00000002 // EP1 TX Double-Packet Buffer - // Disable - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_CTO register. -// -//***************************************************************************** -#define USB_CTO_CCTV_M 0x0000FFFF // Configurable Chirp Timeout Value -#define USB_CTO_CCTV_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_HHSRTN register. -// -//***************************************************************************** -#define USB_HHSRTN_HHSRTN_M 0x0000FFFF // HIgh Speed to UTM Operating +#define MUSB_HHSRTN_HHSRTN_M 0xFFFF // HIgh Speed to UTM Operating // Delay -#define USB_HHSRTN_HHSRTN_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_HSBT register. -// -//***************************************************************************** -#define USB_HSBT_HSBT_M 0x0000000F // High Speed Timeout Adder -#define USB_HSBT_HSBT_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_LPMATTR register. -// -//***************************************************************************** -#define USB_LPMATTR_ENDPT_M 0x0000F000 // Endpoint -#define USB_LPMATTR_RMTWAK 0x00000100 // Remote Wake -#define USB_LPMATTR_HIRD_M 0x000000F0 // Host Initiated Resume Duration -#define USB_LPMATTR_LS_M 0x0000000F // Link State -#define USB_LPMATTR_LS_L1 0x00000001 // Sleep State (L1) -#define USB_LPMATTR_ENDPT_S 12 -#define USB_LPMATTR_HIRD_S 4 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_LPMCNTRL register. -// -//***************************************************************************** -#define USB_LPMCNTRL_NAK 0x00000010 // LPM NAK -#define USB_LPMCNTRL_EN_M 0x0000000C // LPM Enable -#define USB_LPMCNTRL_EN_NONE 0x00000000 // LPM and Extended transactions - // are not supported. In this case, - // the USB does not respond to LPM - // transactions and LPM - // transactions cause a timeout -#define USB_LPMCNTRL_EN_EXT 0x00000004 // LPM is not supported but - // extended transactions are - // supported. In this case, the USB - // does respond to an LPM - // transaction with a STALL -#define USB_LPMCNTRL_EN_LPMEXT 0x0000000C // The USB supports LPM extended - // transactions. In this case, the - // USB responds with a NYET or an - // ACK as determined by the value - // of TXLPM and other conditions -#define USB_LPMCNTRL_RES 0x00000002 // LPM Resume -#define USB_LPMCNTRL_TXLPM 0x00000001 // Transmit LPM Transaction Enable - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_LPMIM register. -// -//***************************************************************************** -#define USB_LPMIM_ERR 0x00000020 // LPM Error Interrupt Mask -#define USB_LPMIM_RES 0x00000010 // LPM Resume Interrupt Mask -#define USB_LPMIM_NC 0x00000008 // LPM NC Interrupt Mask -#define USB_LPMIM_ACK 0x00000004 // LPM ACK Interrupt Mask -#define USB_LPMIM_NY 0x00000002 // LPM NY Interrupt Mask -#define USB_LPMIM_STALL 0x00000001 // LPM STALL Interrupt Mask - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_LPMRIS register. -// -//***************************************************************************** -#define USB_LPMRIS_ERR 0x00000020 // LPM Interrupt Status -#define USB_LPMRIS_RES 0x00000010 // LPM Resume Interrupt Status -#define USB_LPMRIS_NC 0x00000008 // LPM NC Interrupt Status -#define USB_LPMRIS_ACK 0x00000004 // LPM ACK Interrupt Status -#define USB_LPMRIS_NY 0x00000002 // LPM NY Interrupt Status -#define USB_LPMRIS_LPMST 0x00000001 // LPM STALL Interrupt Status - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_LPMFADDR register. -// -//***************************************************************************** -#define USB_LPMFADDR_ADDR_M 0x0000007F // LPM Function Address -#define USB_LPMFADDR_ADDR_S 0 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_EPC register. -// -//***************************************************************************** -#define USB_EPC_PFLTACT_M 0x00000300 // Power Fault Action -#define USB_EPC_PFLTACT_UNCHG 0x00000000 // Unchanged -#define USB_EPC_PFLTACT_TRIS 0x00000100 // Tristate -#define USB_EPC_PFLTACT_LOW 0x00000200 // Low -#define USB_EPC_PFLTACT_HIGH 0x00000300 // High -#define USB_EPC_PFLTAEN 0x00000040 // Power Fault Action Enable -#define USB_EPC_PFLTSEN_HIGH 0x00000020 // Power Fault Sense -#define USB_EPC_PFLTEN 0x00000010 // Power Fault Input Enable -#define USB_EPC_EPENDE 0x00000004 // EPEN Drive Enable -#define USB_EPC_EPEN_M 0x00000003 // External Power Supply Enable - // Configuration -#define USB_EPC_EPEN_LOW 0x00000000 // Power Enable Active Low -#define USB_EPC_EPEN_HIGH 0x00000001 // Power Enable Active High -#define USB_EPC_EPEN_VBLOW 0x00000002 // Power Enable High if VBUS Low - // (OTG only) -#define USB_EPC_EPEN_VBHIGH 0x00000003 // Power Enable High if VBUS High - // (OTG only) - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_EPCRIS register. -// -//***************************************************************************** -#define USB_EPCRIS_PF 0x00000001 // USB Power Fault Interrupt Status - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_EPCIM register. -// -//***************************************************************************** -#define USB_EPCIM_PF 0x00000001 // USB Power Fault Interrupt Mask - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_EPCISC register. -// -//***************************************************************************** -#define USB_EPCISC_PF 0x00000001 // USB Power Fault Interrupt Status - // and Clear - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_DRRIS register. -// -//***************************************************************************** -#define USB_DRRIS_RESUME 0x00000001 // RESUME Interrupt Status - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_DRIM register. -// -//***************************************************************************** -#define USB_DRIM_RESUME 0x00000001 // RESUME Interrupt Mask - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_DRISC register. -// -//***************************************************************************** -#define USB_DRISC_RESUME 0x00000001 // RESUME Interrupt Status and - // Clear - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_GPCS register. -// -//***************************************************************************** -#define USB_GPCS_DEVMOD_M 0x00000007 // Device Mode -#define USB_GPCS_DEVMOD_OTG 0x00000000 // Use USB0VBUS and USB0ID pin -#define USB_GPCS_DEVMOD_HOST 0x00000002 // Force USB0VBUS and USB0ID low -#define USB_GPCS_DEVMOD_DEV 0x00000003 // Force USB0VBUS and USB0ID high -#define USB_GPCS_DEVMOD_HOSTVBUS \ - 0x00000004 // Use USB0VBUS and force USB0ID - // low -#define USB_GPCS_DEVMOD_DEVVBUS 0x00000005 // Use USB0VBUS and force USB0ID - // high - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_VDC register. -// -//***************************************************************************** -#define USB_VDC_VBDEN 0x00000001 // VBUS Droop Enable - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_VDCRIS register. -// -//***************************************************************************** -#define USB_VDCRIS_VD 0x00000001 // VBUS Droop Raw Interrupt Status - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_VDCIM register. -// -//***************************************************************************** -#define USB_VDCIM_VD 0x00000001 // VBUS Droop Interrupt Mask - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_VDCISC register. -// -//***************************************************************************** -#define USB_VDCISC_VD 0x00000001 // VBUS Droop Interrupt Status and - // Clear - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_PP register. -// -//***************************************************************************** -#define USB_PP_ECNT_M 0x0000FF00 // Endpoint Count -#define USB_PP_USB_M 0x000000C0 // USB Capability -#define USB_PP_USB_DEVICE 0x00000040 // DEVICE -#define USB_PP_USB_HOSTDEVICE 0x00000080 // HOST -#define USB_PP_USB_OTG 0x000000C0 // OTG -#define USB_PP_ULPI 0x00000020 // ULPI Present -#define USB_PP_PHY 0x00000010 // PHY Present -#define USB_PP_TYPE_M 0x0000000F // Controller Type -#define USB_PP_TYPE_0 0x00000000 // The first-generation USB - // controller -#define USB_PP_TYPE_1 0x00000001 // The second-generation USB - // controller revision -#define USB_PP_ECNT_S 8 - -//***************************************************************************** -// -// The following are defines for the bit fields in the USB_O_PC register. -// -//***************************************************************************** -#define USB_PC_ULPIEN 0x00010000 // ULPI Enable +#define MUSB_HHSRTN_HHSRTN_S 0 //***************************************************************************** // -// The following are defines for the bit fields in the USB_O_CC register. +// The following are defines for the bit fields in the MUSB_O_HSBT register. // //***************************************************************************** -#define USB_CC_CLKEN 0x00000200 // USB Clock Enable -#define USB_CC_CSD 0x00000100 // Clock Source/Direction -#define USB_CC_CLKDIV_M 0x0000000F // PLL Clock Divisor -#define USB_CC_CLKDIV_S 0 +#define MUSB_HSBT_HSBT_M 0x000F // High Speed Timeout Adder +#define MUSB_HSBT_HSBT_S 0 #ifdef __cplusplus } diff --git a/src/portable/microchip/samg/dcd_samg.c b/src/portable/microchip/samg/dcd_samg.c index e3fa51e31..a15431937 100644 --- a/src/portable/microchip/samg/dcd_samg.c +++ b/src/portable/microchip/samg/dcd_samg.c @@ -277,6 +277,11 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * ep_desc) return true; } +void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) { + (void) rhport; (void) ep_addr; + // TODO implement dcd_edpt_close() +} + void dcd_edpt_close_all (uint8_t rhport) { (void) rhport; diff --git a/src/portable/nordic/nrf5x/dcd_nrf5x.c b/src/portable/nordic/nrf5x/dcd_nrf5x.c index 1cc5c1836..a63e442f3 100644 --- a/src/portable/nordic/nrf5x/dcd_nrf5x.c +++ b/src/portable/nordic/nrf5x/dcd_nrf5x.c @@ -441,11 +441,11 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t to bool const control_status = (epnum == 0 && total_bytes == 0 && dir != tu_edpt_dir(NRF_USBD->BMREQUESTTYPE)); if (control_status) { - // Status Phase also requires EasyDMA has to be available as well !!!! - edpt_dma_start(&NRF_USBD->TASKS_EP0STATUS); - // The nRF doesn't interrupt on status transmit so we queue up a success response. dcd_event_xfer_complete(0, ep_addr, 0, XFER_RESULT_SUCCESS, is_in_isr()); + + // Status Phase also requires EasyDMA has to be available as well !!!! + edpt_dma_start(&NRF_USBD->TASKS_EP0STATUS); } else if (dir == TUSB_DIR_OUT) { xfer->started = true; if (epnum == 0) { diff --git a/src/portable/nxp/lpc17_40/dcd_lpc17_40.c b/src/portable/nxp/lpc17_40/dcd_lpc17_40.c index b880c2870..75b29faf3 100644 --- a/src/portable/nxp/lpc17_40/dcd_lpc17_40.c +++ b/src/portable/nxp/lpc17_40/dcd_lpc17_40.c @@ -335,6 +335,11 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) return true; } +void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) { + (void) rhport; (void) ep_addr; + // TODO implement dcd_edpt_close() +} + void dcd_edpt_close_all (uint8_t rhport) { (void) rhport; diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.c b/src/portable/raspberrypi/rp2040/rp2040_usb.c index 1ca711c77..43f48da39 100644 --- a/src/portable/raspberrypi/rp2040/rp2040_usb.c +++ b/src/portable/raspberrypi/rp2040/rp2040_usb.c @@ -53,6 +53,14 @@ TU_ATTR_ALWAYS_INLINE static inline bool is_host_mode(void) { //--------------------------------------------------------------------+ // Implementation //--------------------------------------------------------------------+ +// Provide own byte by byte memcpy as not all copies are aligned +static void unaligned_memcpy(void *dst, const void *src, size_t n) { + uint8_t *dst_byte = (uint8_t*)dst; + const uint8_t *src_byte = (const uint8_t*)src; + while (n--) { + *dst_byte++ = *src_byte++; + } +} void rp2040_usb_init(void) { // Reset usb controller @@ -67,7 +75,6 @@ void rp2040_usb_init(void) { #pragma GCC diagnostic ignored "-Wstringop-overflow" #endif #endif - memset(usb_hw, 0, sizeof(*usb_hw)); memset(usb_dpram, 0, sizeof(*usb_dpram)); #ifdef __GNUC__ #pragma GCC diagnostic pop @@ -125,7 +132,7 @@ static uint32_t __tusb_irq_path_func(prepare_ep_buffer)(struct hw_endpoint* ep, if (!ep->rx) { // Copy data from user buffer to hw buffer - memcpy(ep->hw_data_buf + buf_id * 64, ep->user_buf, buflen); + unaligned_memcpy(ep->hw_data_buf + buf_id * 64, ep->user_buf, buflen); ep->user_buf += buflen; // Mark as full @@ -230,7 +237,7 @@ static uint16_t __tusb_irq_path_func(sync_ep_buffer)(struct hw_endpoint* ep, uin // we have received AFTER we have copied it to the user buffer at the appropriate offset assert(buf_ctrl & USB_BUF_CTRL_FULL); - memcpy(ep->user_buf, ep->hw_data_buf + buf_id * 64, xferred_bytes); + unaligned_memcpy(ep->user_buf, ep->hw_data_buf + buf_id * 64, xferred_bytes); ep->xferred_len = (uint16_t) (ep->xferred_len + xferred_bytes); ep->user_buf += xferred_bytes; } diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c index 8bfb899ca..6eea1ab32 100644 --- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c +++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c @@ -4,7 +4,6 @@ * Copyright (c) 2019 Nathan Conrad * * Portions: - * Copyright (c) 2016 STMicroelectronics * Copyright (c) 2019 Ha Thach (tinyusb.org) * Copyright (c) 2022 Simon Küppers (skuep) * Copyright (c) 2022 HiFiPhile @@ -114,8 +113,6 @@ #include "device/dcd.h" #if defined(TUP_USBIP_FSDEV_STM32) - // Undefine to reduce the dependence on HAL - #undef USE_HAL_DRIVER #include "fsdev_stm32.h" #elif defined(TUP_USBIP_FSDEV_CH32) #include "fsdev_ch32.h" @@ -123,27 +120,7 @@ #error "Unknown USB IP" #endif -#include "fsdev_common.h" - -//--------------------------------------------------------------------+ -// Configuration -//--------------------------------------------------------------------+ - -// hardware limit endpoint -#define FSDEV_EP_COUNT 8 - -// If sharing with CAN, one can set this to be non-zero to give CAN space where it wants it -// Both of these MUST be a multiple of 2, and are in byte units. -#ifndef DCD_STM32_BTABLE_BASE -#define DCD_STM32_BTABLE_BASE 0U -#endif - -#ifndef DCD_STM32_BTABLE_SIZE -#define DCD_STM32_BTABLE_SIZE (FSDEV_PMA_SIZE - DCD_STM32_BTABLE_BASE) -#endif - -TU_VERIFY_STATIC(((DCD_STM32_BTABLE_BASE) + (DCD_STM32_BTABLE_SIZE)) <= (FSDEV_PMA_SIZE), "BTABLE does not fit in PMA RAM"); -TU_VERIFY_STATIC(((DCD_STM32_BTABLE_BASE) % 8) == 0, "BTABLE base must be aligned to 8 bytes"); +#include "fsdev_type.h" //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF @@ -168,11 +145,7 @@ typedef struct { } ep_alloc_t; static xfer_ctl_t xfer_status[CFG_TUD_ENDPPOINT_MAX][2]; - static ep_alloc_t ep_alloc_status[FSDEV_EP_COUNT]; - -static TU_ATTR_ALIGNED(4) uint32_t _setup_packet[6]; - static uint8_t remoteWakeCountdown; // When wake is requested //--------------------------------------------------------------------+ @@ -180,99 +153,90 @@ static uint8_t remoteWakeCountdown; // When wake is requested //--------------------------------------------------------------------+ // into the stack. -static void dcd_handle_bus_reset(void); +static void handle_bus_reset(uint8_t rhport); static void dcd_transmit_packet(xfer_ctl_t *xfer, uint16_t ep_ix); -static bool edpt_xfer(uint8_t rhport, uint8_t ep_addr); -static void dcd_ep_ctr_handler(void); +static bool edpt_xfer(uint8_t rhport, uint8_t ep_num, tusb_dir_t dir); // PMA allocation/access static uint16_t ep_buf_ptr; ///< Points to first free memory location -static uint32_t dcd_pma_alloc(uint16_t length, bool dbuf); +static uint32_t dcd_pma_alloc(uint16_t len, bool dbuf); static uint8_t dcd_ep_alloc(uint8_t ep_addr, uint8_t ep_type); -static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, uint16_t wNBytes); -static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, uint16_t wNBytes); +static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, uint16_t nbytes); +static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, uint16_t nbytes); static bool dcd_write_packet_memory_ff(tu_fifo_t *ff, uint16_t dst, uint16_t wNBytes); static bool dcd_read_packet_memory_ff(tu_fifo_t *ff, uint16_t src, uint16_t wNBytes); +static void edpt0_open(uint8_t rhport); + +TU_ATTR_ALWAYS_INLINE static inline void edpt0_prepare_setup(void) { + btable_set_rx_bufsize(0, BTABLE_BUF_RX, 8); +} + //--------------------------------------------------------------------+ // Inline helper //--------------------------------------------------------------------+ -TU_ATTR_ALWAYS_INLINE static inline xfer_ctl_t *xfer_ctl_ptr(uint32_t ep_addr) -{ - uint8_t epnum = tu_edpt_number(ep_addr); - uint8_t dir = tu_edpt_dir(ep_addr); - // Fix -Werror=null-dereference - TU_ASSERT(epnum < CFG_TUD_ENDPPOINT_MAX, &xfer_status[0][0]); - +TU_ATTR_ALWAYS_INLINE static inline xfer_ctl_t *xfer_ctl_ptr(uint8_t epnum, uint8_t dir) { return &xfer_status[epnum][dir]; } //--------------------------------------------------------------------+ // Controller API //--------------------------------------------------------------------+ - -void dcd_init(uint8_t rhport) -{ - /* Clocks should already be enabled */ - /* Use __HAL_RCC_USB_CLK_ENABLE(); to enable the clocks before calling this function */ - - /* The RM mentions to use a special ordering of PDWN and FRES, but this isn't done in HAL. - * Here, the RM is followed. */ - +void dcd_init(uint8_t rhport) { + // Follow the RM mentions to use a special ordering of PDWN and FRES for (volatile uint32_t i = 0; i < 200; i++) { // should be a few us asm("NOP"); } + // Perform USB peripheral reset - USB->CNTR = USB_CNTR_FRES | USB_CNTR_PDWN; + FSDEV_REG->CNTR = USB_CNTR_FRES | USB_CNTR_PDWN; for (volatile uint32_t i = 0; i < 200; i++) { // should be a few us asm("NOP"); } - USB->CNTR &= ~USB_CNTR_PDWN; + FSDEV_REG->CNTR &= ~USB_CNTR_PDWN; // Wait startup time, for F042 and F070, this is <= 1 us. for (volatile uint32_t i = 0; i < 200; i++) { // should be a few us asm("NOP"); } - USB->CNTR = 0; // Enable USB + FSDEV_REG->CNTR = 0; // Enable USB -#if !defined(STM32G0) && !defined(STM32H5) && !defined(STM32U5) // BTABLE register does not exist any more on STM32G0, it is fixed to USB SRAM base address - USB->BTABLE = DCD_STM32_BTABLE_BASE; +#if !defined(FSDEV_BUS_32BIT) + // BTABLE register does not exist any more on 32-bit bus devices + FSDEV_REG->BTABLE = FSDEV_BTABLE_BASE; #endif - USB->ISTR = 0; // Clear pending interrupts + + FSDEV_REG->ISTR = 0; // Clear pending interrupts // Reset endpoints to disabled for (uint32_t i = 0; i < FSDEV_EP_COUNT; i++) { // This doesn't clear all bits since some bits are "toggle", but does set the type to DISABLED. - pcd_set_endpoint(USB, i, 0u); + ep_write(i, 0u, false); } - USB->CNTR |= USB_CNTR_RESETM | USB_CNTR_ESOFM | USB_CNTR_CTRM | USB_CNTR_SUSPM | USB_CNTR_WKUPM; - dcd_handle_bus_reset(); + FSDEV_REG->CNTR |= USB_CNTR_RESETM | USB_CNTR_ESOFM | USB_CNTR_CTRM | + USB_CNTR_SUSPM | USB_CNTR_WKUPM | USB_CNTR_PMAOVRM; + handle_bus_reset(rhport); // Enable pull-up if supported dcd_connect(rhport); } - -void dcd_sof_enable(uint8_t rhport, bool en) -{ +void dcd_sof_enable(uint8_t rhport, bool en) { (void)rhport; - (void)en; if (en) { - USB->CNTR |= USB_CNTR_SOFM; + FSDEV_REG->CNTR |= USB_CNTR_SOFM; } else { - USB->CNTR &= ~USB_CNTR_SOFM; + FSDEV_REG->CNTR &= ~USB_CNTR_SOFM; } } // Receive Set Address request, mcu port must also include status IN response -void dcd_set_address(uint8_t rhport, uint8_t dev_addr) -{ - (void)rhport; +void dcd_set_address(uint8_t rhport, uint8_t dev_addr) { (void)dev_addr; // Respond with status @@ -282,35 +246,15 @@ void dcd_set_address(uint8_t rhport, uint8_t dev_addr) // do it at dcd_edpt0_status_complete() } -void dcd_remote_wakeup(uint8_t rhport) -{ +void dcd_remote_wakeup(uint8_t rhport) { (void)rhport; - USB->CNTR |= USB_CNTR_RESUME; + FSDEV_REG->CNTR |= USB_CNTR_RESUME; remoteWakeCountdown = 4u; // required to be 1 to 15 ms, ESOF should trigger every 1ms. } -static const tusb_desc_endpoint_t ep0OUT_desc = { - .bLength = sizeof(tusb_desc_endpoint_t), - .bDescriptorType = TUSB_DESC_ENDPOINT, - .bEndpointAddress = 0x00, - .bmAttributes = {.xfer = TUSB_XFER_CONTROL}, - .wMaxPacketSize = CFG_TUD_ENDPOINT0_SIZE, - .bInterval = 0 -}; - -static const tusb_desc_endpoint_t ep0IN_desc = { - .bLength = sizeof(tusb_desc_endpoint_t), - .bDescriptorType = TUSB_DESC_ENDPOINT, - .bEndpointAddress = 0x80, - .bmAttributes = {.xfer = TUSB_XFER_CONTROL}, - .wMaxPacketSize = CFG_TUD_ENDPOINT0_SIZE, - .bInterval = 0 -}; - -static void dcd_handle_bus_reset(void) -{ - USB->DADDR = 0u; // disable USB peripheral by clearing the EF flag +static void handle_bus_reset(uint8_t rhport) { + FSDEV_REG->DADDR = 0u; // disable USB Function for (uint32_t i = 0; i < FSDEV_EP_COUNT; i++) { // Clear EP allocation status @@ -321,35 +265,21 @@ static void dcd_handle_bus_reset(void) } // Reset PMA allocation - ep_buf_ptr = DCD_STM32_BTABLE_BASE + 8 * CFG_TUD_ENDPPOINT_MAX; + ep_buf_ptr = FSDEV_BTABLE_BASE + 8 * FSDEV_EP_COUNT; - dcd_edpt_open(0, &ep0OUT_desc); - dcd_edpt_open(0, &ep0IN_desc); + edpt0_open(rhport); // open control endpoint (both IN & OUT) - USB->DADDR = USB_DADDR_EF; // Set enable flag, and leaving the device address as zero. + FSDEV_REG->DADDR = USB_DADDR_EF; // Enable USB Function } // Handle CTR interrupt for the TX/IN direction -// -// Upon call, (wIstr & USB_ISTR_DIR) == 0U -static void dcd_ep_ctr_tx_handler(uint32_t wIstr) -{ - uint32_t EPindex = wIstr & USB_ISTR_EP_ID; - uint32_t wEPRegVal = pcd_get_endpoint(USB, EPindex); - uint8_t ep_addr = (wEPRegVal & USB_EPADDR_FIELD) | TUSB_DIR_IN_MASK; - - // Verify the CTR_TX bit is set. This was in the ST Micro code, - // but I'm not sure it's actually necessary? - if ((wEPRegVal & USB_EP_CTR_TX) == 0U) { - return; - } - - /* clear int flag */ - pcd_clear_tx_ep_ctr(USB, EPindex); +static void handle_ctr_tx(uint32_t ep_id) { + uint32_t ep_reg = ep_read(ep_id) | USB_EP_CTR_TX | USB_EP_CTR_RX; - xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr); + uint8_t const ep_num = ep_reg & USB_EPADDR_FIELD; + xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, TUSB_DIR_IN); - if ((wEPRegVal & USB_EP_TYPE_MASK) == USB_EP_ISOCHRONOUS) { + if (ep_is_iso(ep_reg)) { // Ignore spurious interrupts that we don't schedule // host can send IN token while there is no data to send, since ISO does not have NAK // this will result to zero length packet --> trigger interrupt (which cannot be masked) @@ -357,189 +287,106 @@ static void dcd_ep_ctr_tx_handler(uint32_t wIstr) return; } xfer->iso_in_sending = false; - - if (wEPRegVal & USB_EP_DTOG_TX) { - pcd_set_ep_tx_dbuf0_cnt(USB, EPindex, 0); - } else { - pcd_set_ep_tx_dbuf1_cnt(USB, EPindex, 0); - } + uint8_t buf_id = (ep_reg & USB_EP_DTOG_TX) ? 0 : 1; + btable_set_count(ep_id, buf_id, 0); } - if ((xfer->total_len != xfer->queued_len)) { - dcd_transmit_packet(xfer, EPindex); + if (xfer->total_len != xfer->queued_len) { + dcd_transmit_packet(xfer, ep_id); } else { - dcd_event_xfer_complete(0, ep_addr, xfer->total_len, XFER_RESULT_SUCCESS, true); + dcd_event_xfer_complete(0, ep_num | TUSB_DIR_IN_MASK, xfer->queued_len, XFER_RESULT_SUCCESS, true); } } -// Handle CTR interrupt for the RX/OUT direction -// Upon call, (wIstr & USB_ISTR_DIR) == 0U -static void dcd_ep_ctr_rx_handler(uint32_t wIstr) -{ -#ifdef FSDEV_BUS_32BIT - /* https://www.st.com/resource/en/errata_sheet/es0561-stm32h503cbebkbrb-device-errata-stmicroelectronics.pdf - * From STM32H503 errata 2.15.1: Buffer description table update completes after CTR interrupt triggers - * Description: - * - During OUT transfers, the correct transfer interrupt (CTR) is triggered a little before the last USB SRAM accesses - * have completed. If the software responds quickly to the interrupt, the full buffer contents may not be correct. - * Workaround: - * - Software should ensure that a small delay is included before accessing the SRAM contents. This delay - * should be 800 ns in Full Speed mode and 6.4 μs in Low Speed mode - * - Since H5 can run up to 250Mhz -> 1 cycle = 4ns. Per errata, we need to wait 200 cycles. Though executing code - * also takes time, so we'll wait 60 cycles (count = 20). - * - Since Low Speed mode is not supported/popular, we will ignore it for now. - * - * Note: this errata also seems to apply to G0, U5, H5 etc. - */ - volatile uint32_t cycle_count = 20; // defined as PCD_RX_PMA_CNT in stm32 hal_driver - while (cycle_count > 0U) { - cycle_count--; // each count take 3 cycles (1 for sub, jump, and compare) - } -#endif - - uint32_t EPindex = wIstr & USB_ISTR_EP_ID; - uint32_t wEPRegVal = pcd_get_endpoint(USB, EPindex); - uint8_t ep_addr = wEPRegVal & USB_EPADDR_FIELD; +static void handle_ctr_setup(uint32_t ep_id) { + uint16_t rx_count = btable_get_count(ep_id, BTABLE_BUF_RX); + uint16_t rx_addr = btable_get_addr(ep_id, BTABLE_BUF_RX); + uint8_t setup_packet[8] TU_ATTR_ALIGNED(4); - xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr); + dcd_read_packet_memory(setup_packet, rx_addr, rx_count); - // Verify the CTR_RX bit is set. This was in the ST Micro code, - // but I'm not sure it's actually necessary? - if ((wEPRegVal & USB_EP_CTR_RX) == 0U) { - return; - } + // Clear CTR RX if another setup packet arrived before this, it will be discarded + ep_write_clear_ctr(ep_id, TUSB_DIR_OUT); - if ((ep_addr == 0U) && ((wEPRegVal & USB_EP_SETUP) != 0U)) { - /* Setup packet */ - uint32_t count = pcd_get_ep_rx_cnt(USB, EPindex); - // Setup packet should always be 8 bytes. If not, ignore it, and try again. - if (count == 8) { - // Must reset EP to NAK (in case it had been stalling) (though, maybe too late here) - pcd_set_ep_rx_status(USB, 0u, USB_EP_RX_NAK); - pcd_set_ep_tx_status(USB, 0u, USB_EP_TX_NAK); -#ifdef FSDEV_BUS_32BIT - dcd_event_setup_received(0, (uint8_t *)(USB_PMAADDR + pcd_get_ep_rx_address(USB, EPindex)), true); -#else - // The setup_received function uses memcpy, so this must first copy the setup data into - // user memory, to allow for the 32-bit access that memcpy performs. - uint8_t userMemBuf[8]; - dcd_read_packet_memory(userMemBuf, pcd_get_ep_rx_address(USB, EPindex), 8); - dcd_event_setup_received(0, (uint8_t *)userMemBuf, true); -#endif - } + // Setup packet should always be 8 bytes. If not, we probably missed the packet + if (rx_count == 8) { + dcd_event_setup_received(0, (uint8_t*) setup_packet, true); + // Hardware should reset EP0 RX/TX to NAK and both toggle to 1 } else { - // Clear RX CTR interrupt flag - if (ep_addr != 0u) { - pcd_clear_rx_ep_ctr(USB, EPindex); - } - - uint32_t count; - uint16_t addr; - /* Read from correct register when ISOCHRONOUS (double buffered) */ - if ((wEPRegVal & USB_EP_TYPE_MASK) == USB_EP_ISOCHRONOUS) { - if (wEPRegVal & USB_EP_DTOG_RX) { - count = pcd_get_ep_dbuf0_cnt(USB, EPindex); - addr = pcd_get_ep_dbuf0_address(USB, EPindex); - } else { - count = pcd_get_ep_dbuf1_cnt(USB, EPindex); - addr = pcd_get_ep_dbuf1_address(USB, EPindex); - } - } else { - count = pcd_get_ep_rx_cnt(USB, EPindex); - addr = pcd_get_ep_rx_address(USB, EPindex); - } - - TU_ASSERT(count <= xfer->max_packet_size, /**/); - - if (count != 0U) { - if (xfer->ff) { - dcd_read_packet_memory_ff(xfer->ff, addr, count); - } else { - dcd_read_packet_memory(&(xfer->buffer[xfer->queued_len]), addr, count); - } + // Missed setup packet !!! + TU_BREAKPOINT(); + edpt0_prepare_setup(); + } +} - xfer->queued_len = (uint16_t)(xfer->queued_len + count); - } +// Handle CTR interrupt for the RX/OUT direction +static void handle_ctr_rx(uint32_t ep_id) { + uint32_t ep_reg = ep_read(ep_id) | USB_EP_CTR_TX | USB_EP_CTR_RX; + uint8_t const ep_num = ep_reg & USB_EPADDR_FIELD; + bool const is_iso = ep_is_iso(ep_reg); + xfer_ctl_t* xfer = xfer_ctl_ptr(ep_num, TUSB_DIR_OUT); - if ((count < xfer->max_packet_size) || (xfer->queued_len == xfer->total_len)) { - // all bytes received or short packet - dcd_event_xfer_complete(0, ep_addr, xfer->queued_len, XFER_RESULT_SUCCESS, true); - } else { - /* Set endpoint active again for receiving more data. - * Note that isochronous endpoints stay active always */ - if ((wEPRegVal & USB_EP_TYPE_MASK) != USB_EP_ISOCHRONOUS) { - uint16_t remaining = xfer->total_len - xfer->queued_len; - uint16_t cnt = tu_min16(remaining, xfer->max_packet_size); - pcd_set_ep_rx_cnt(USB, EPindex, cnt); - } - pcd_set_ep_rx_status(USB, EPindex, USB_EP_RX_VALID); - } + uint8_t buf_id; + if (is_iso) { + buf_id = (ep_reg & USB_EP_DTOG_RX) ? 0 : 1; // ISO are double buffered + } else { + buf_id = BTABLE_BUF_RX; } + uint16_t const rx_count = btable_get_count(ep_id, buf_id); + uint16_t pma_addr = (uint16_t) btable_get_addr(ep_id, buf_id); - // For EP0, prepare to receive another SETUP packet. - // Clear CTR last so that a new packet does not overwrite the packing being read. - // (Based on the docs, it seems SETUP will always be accepted after CTR is cleared) - if (ep_addr == 0u) { - // Always be prepared for a status packet... - pcd_set_ep_rx_cnt(USB, EPindex, CFG_TUD_ENDPOINT0_SIZE); - pcd_clear_rx_ep_ctr(USB, EPindex); + if (xfer->ff) { + dcd_read_packet_memory_ff(xfer->ff, pma_addr, rx_count); + } else { + dcd_read_packet_memory(xfer->buffer + xfer->queued_len, pma_addr, rx_count); } -} + xfer->queued_len += rx_count; -static void dcd_ep_ctr_handler(void) -{ - uint32_t wIstr; + if ((rx_count < xfer->max_packet_size) || (xfer->queued_len >= xfer->total_len)) { + // all bytes received or short packet - /* stay in loop while pending interrupts */ - while (((wIstr = USB->ISTR) & USB_ISTR_CTR) != 0U) { - if ((wIstr & USB_ISTR_DIR) == 0U) { - /* TX/IN */ - dcd_ep_ctr_tx_handler(wIstr); - } else { - /* RX/OUT*/ - dcd_ep_ctr_rx_handler(wIstr); + // For ch32v203: reset rx bufsize to mps to prevent race condition to cause PMAOVR (occurs with msc write10) + btable_set_rx_bufsize(ep_id, BTABLE_BUF_RX, xfer->max_packet_size); + + dcd_event_xfer_complete(0, ep_num, xfer->queued_len, XFER_RESULT_SUCCESS, true); + + // ch32 seems to unconditionally accept ZLP on EP0 OUT, which can incorrectly use queued_len of previous + // transfer. So reset total_len and queued_len to 0. + xfer->total_len = xfer->queued_len = 0; + } else { + // Set endpoint active again for receiving more data. Note that isochronous endpoints stay active always + if (!is_iso) { + uint16_t const cnt = tu_min16(xfer->total_len - xfer->queued_len, xfer->max_packet_size); + btable_set_rx_bufsize(ep_id, BTABLE_BUF_RX, cnt); } + ep_reg &= USB_EPREG_MASK | EP_STAT_MASK(TUSB_DIR_OUT); // will change RX Status, reserved other toggle bits + ep_change_status(&ep_reg, TUSB_DIR_OUT, EP_STAT_VALID); + ep_write(ep_id, ep_reg, false); } } -void dcd_int_handler(uint8_t rhport) -{ - (void)rhport; - - uint32_t int_status = USB->ISTR; - // const uint32_t handled_ints = USB_ISTR_CTR | USB_ISTR_RESET | USB_ISTR_WKUP - // | USB_ISTR_SUSP | USB_ISTR_SOF | USB_ISTR_ESOF; - // unused IRQs: (USB_ISTR_PMAOVR | USB_ISTR_ERR | USB_ISTR_L1REQ ) - - // The ST driver loops here on the CTR bit, but that loop has been moved into the - // dcd_ep_ctr_handler(), so less need to loop here. The other interrupts shouldn't - // be triggered repeatedly. +void dcd_int_handler(uint8_t rhport) { + uint32_t int_status = FSDEV_REG->ISTR; /* Put SOF flag at the beginning of ISR in case to get least amount of jitter if it is used for timing purposes */ if (int_status & USB_ISTR_SOF) { - USB->ISTR = (fsdev_bus_t)~USB_ISTR_SOF; - dcd_event_sof(0, USB->FNR & USB_FNR_FN, true); + FSDEV_REG->ISTR = (fsdev_bus_t)~USB_ISTR_SOF; + dcd_event_sof(0, FSDEV_REG->FNR & USB_FNR_FN, true); } if (int_status & USB_ISTR_RESET) { // USBRST is start of reset. - USB->ISTR = (fsdev_bus_t)~USB_ISTR_RESET; - dcd_handle_bus_reset(); + FSDEV_REG->ISTR = (fsdev_bus_t)~USB_ISTR_RESET; + handle_bus_reset(rhport); dcd_event_bus_reset(0, TUSB_SPEED_FULL, true); return; // Don't do the rest of the things here; perhaps they've been cleared? } - if (int_status & USB_ISTR_CTR) { - /* servicing of the endpoint correct transfer interrupt */ - /* clear of the CTR flag into the sub */ - dcd_ep_ctr_handler(); - } - if (int_status & USB_ISTR_WKUP) { - USB->CNTR &= ~USB_CNTR_LPMODE; - USB->CNTR &= ~USB_CNTR_FSUSP; + FSDEV_REG->CNTR &= ~USB_CNTR_LPMODE; + FSDEV_REG->CNTR &= ~USB_CNTR_FSUSP; - USB->ISTR = (fsdev_bus_t)~USB_ISTR_WKUP; + FSDEV_REG->ISTR = (fsdev_bus_t)~USB_ISTR_WKUP; dcd_event_bus_signal(0, DCD_EVENT_RESUME, true); } @@ -548,22 +395,70 @@ void dcd_int_handler(uint8_t rhport) * these events cannot be differentiated, so we only trigger suspend. */ /* Force low-power mode in the macrocell */ - USB->CNTR |= USB_CNTR_FSUSP; - USB->CNTR |= USB_CNTR_LPMODE; + FSDEV_REG->CNTR |= USB_CNTR_FSUSP; + FSDEV_REG->CNTR |= USB_CNTR_LPMODE; /* clear of the ISTR bit must be done after setting of CNTR_FSUSP */ - USB->ISTR = (fsdev_bus_t)~USB_ISTR_SUSP; + FSDEV_REG->ISTR = (fsdev_bus_t)~USB_ISTR_SUSP; dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true); } if (int_status & USB_ISTR_ESOF) { if (remoteWakeCountdown == 1u) { - USB->CNTR &= ~USB_CNTR_RESUME; + FSDEV_REG->CNTR &= ~USB_CNTR_RESUME; } if (remoteWakeCountdown > 0u) { remoteWakeCountdown--; } - USB->ISTR = (fsdev_bus_t)~USB_ISTR_ESOF; + FSDEV_REG->ISTR = (fsdev_bus_t)~USB_ISTR_ESOF; + } + + // loop to handle all pending CTR interrupts + while (FSDEV_REG->ISTR & USB_ISTR_CTR) { + // skip DIR bit, and use CTR TX/RX instead, since there is chance we have both TX/RX completed in one interrupt + uint32_t const ep_id = FSDEV_REG->ISTR & USB_ISTR_EP_ID; + uint32_t const ep_reg = ep_read(ep_id); + + if (ep_reg & USB_EP_CTR_RX) { + #ifdef FSDEV_BUS_32BIT + /* https://www.st.com/resource/en/errata_sheet/es0561-stm32h503cbebkbrb-device-errata-stmicroelectronics.pdf + * https://www.st.com/resource/en/errata_sheet/es0587-stm32u535xx-and-stm32u545xx-device-errata-stmicroelectronics.pdf + * From H503/U535 errata: Buffer description table update completes after CTR interrupt triggers + * Description: + * - During OUT transfers, the correct transfer interrupt (CTR) is triggered a little before the last USB SRAM accesses + * have completed. If the software responds quickly to the interrupt, the full buffer contents may not be correct. + * Workaround: + * - Software should ensure that a small delay is included before accessing the SRAM contents. This delay + * should be 800 ns in Full Speed mode and 6.4 μs in Low Speed mode + * - Since H5 can run up to 250Mhz -> 1 cycle = 4ns. Per errata, we need to wait 200 cycles. Though executing code + * also takes time, so we'll wait 60 cycles (count = 20). + * - Since Low Speed mode is not supported/popular, we will ignore it for now. + * + * Note: this errata may also apply to G0, U5, H5 etc. + */ + volatile uint32_t cycle_count = 20; // defined as PCD_RX_PMA_CNT in stm32 hal_driver + while (cycle_count > 0U) { + cycle_count--; // each count take 3 cycles (1 for sub, jump, and compare) + } + #endif + + if (ep_reg & USB_EP_SETUP) { + handle_ctr_setup(ep_id); // CTR will be clear after copied setup packet + } else { + ep_write_clear_ctr(ep_id, TUSB_DIR_OUT); + handle_ctr_rx(ep_id); + } + } + + if (ep_reg & USB_EP_CTR_TX) { + ep_write_clear_ctr(ep_id, TUSB_DIR_IN); + handle_ctr_tx(ep_id); + } + } + + if (int_status & USB_ISTR_PMAOVR) { + TU_BREAKPOINT(); + FSDEV_REG->ISTR = (fsdev_bus_t)~USB_ISTR_PMAOVR; } } @@ -573,19 +468,17 @@ void dcd_int_handler(uint8_t rhport) // Invoked when a control transfer's status stage is complete. // May help DCD to prepare for next control transfer, this API is optional. -void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const *request) -{ +void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const *request) { (void)rhport; if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE && request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD && request->bRequest == TUSB_REQ_SET_ADDRESS) { uint8_t const dev_addr = (uint8_t)request->wValue; - - // Setting new address after the whole request is complete - USB->DADDR &= ~USB_DADDR_ADD; - USB->DADDR |= dev_addr; // leave the enable bit set + FSDEV_REG->DADDR = (USB_DADDR_EF | dev_addr); } + + edpt0_prepare_setup(); } /*** @@ -593,21 +486,19 @@ void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const *req * In case of double buffering, high 16bit is the address of 2nd buffer * During failure, TU_ASSERT is used. If this happens, rework/reallocate memory manually. */ -static uint32_t dcd_pma_alloc(uint16_t length, bool dbuf) +static uint32_t dcd_pma_alloc(uint16_t len, bool dbuf) { - // Ensure allocated buffer is aligned -#ifdef FSDEV_BUS_32BIT - length = (length + 3) & ~0x03; -#else - length = (length + 1) & ~0x01; -#endif + uint8_t blsize, num_block; + uint16_t aligned_len = pma_align_buffer_size(len, &blsize, &num_block); + (void) blsize; + (void) num_block; uint32_t addr = ep_buf_ptr; - ep_buf_ptr = (uint16_t)(ep_buf_ptr + length); // increment buffer pointer + ep_buf_ptr = (uint16_t)(ep_buf_ptr + aligned_len); // increment buffer pointer if (dbuf) { addr |= ((uint32_t)ep_buf_ptr) << 16; - ep_buf_ptr = (uint16_t)(ep_buf_ptr + length); // increment buffer pointer + ep_buf_ptr = (uint16_t)(ep_buf_ptr + aligned_len); // increment buffer pointer } // Verify packet buffer is not overflowed @@ -654,34 +545,53 @@ static uint8_t dcd_ep_alloc(uint8_t ep_addr, uint8_t ep_type) TU_ASSERT(0); } -// The STM32F0 doesn't seem to like |= or &= to manipulate the EP#R registers, -// so I'm using the #define from HAL here, instead. +void edpt0_open(uint8_t rhport) { + (void) rhport; -bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *p_endpoint_desc) -{ - (void)rhport; - uint8_t const ep_addr = p_endpoint_desc->bEndpointAddress; - uint8_t const ep_idx = dcd_ep_alloc(ep_addr, p_endpoint_desc->bmAttributes.xfer); - uint8_t const dir = tu_edpt_dir(ep_addr); - const uint16_t packet_size = tu_edpt_packet_size(p_endpoint_desc); - const uint16_t buffer_size = pcd_aligned_buffer_size(packet_size); - uint16_t pma_addr; - uint32_t wType; + dcd_ep_alloc(0x0, TUSB_XFER_CONTROL); + dcd_ep_alloc(0x80, TUSB_XFER_CONTROL); + + xfer_status[0][0].max_packet_size = CFG_TUD_ENDPOINT0_SIZE; + xfer_status[0][0].ep_idx = 0; + + xfer_status[0][1].max_packet_size = CFG_TUD_ENDPOINT0_SIZE; + xfer_status[0][1].ep_idx = 0; + + uint16_t pma_addr0 = dcd_pma_alloc(CFG_TUD_ENDPOINT0_SIZE, false); + uint16_t pma_addr1 = dcd_pma_alloc(CFG_TUD_ENDPOINT0_SIZE, false); + + btable_set_addr(0, BTABLE_BUF_RX, pma_addr0); + btable_set_addr(0, BTABLE_BUF_TX, pma_addr1); + + uint32_t ep_reg = ep_read(0) & ~USB_EPREG_MASK; // only get toggle bits + ep_reg |= USB_EP_CONTROL; + ep_change_status(&ep_reg, TUSB_DIR_IN, EP_STAT_NAK); + ep_change_status(&ep_reg, TUSB_DIR_OUT, EP_STAT_NAK); + // no need to explicitly set DTOG bits since we aren't masked DTOG bit + edpt0_prepare_setup(); // prepare for setup packet + ep_write(0, ep_reg, false); +} + +bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *desc_ep) { + (void)rhport; + uint8_t const ep_addr = desc_ep->bEndpointAddress; + uint8_t const ep_num = tu_edpt_number(ep_addr); + tusb_dir_t const dir = tu_edpt_dir(ep_addr); + const uint16_t packet_size = tu_edpt_packet_size(desc_ep); + uint8_t const ep_idx = dcd_ep_alloc(ep_addr, desc_ep->bmAttributes.xfer); TU_ASSERT(ep_idx < FSDEV_EP_COUNT); - TU_ASSERT(buffer_size <= 64); + + uint32_t ep_reg = ep_read(ep_idx) & ~USB_EPREG_MASK; + ep_reg |= tu_edpt_number(ep_addr) | USB_EP_CTR_TX | USB_EP_CTR_RX; // Set type - switch (p_endpoint_desc->bmAttributes.xfer) { - case TUSB_XFER_CONTROL: - wType = USB_EP_CONTROL; - break; + switch (desc_ep->bmAttributes.xfer) { case TUSB_XFER_BULK: - wType = USB_EP_CONTROL; + ep_reg |= USB_EP_BULK; break; - case TUSB_XFER_INTERRUPT: - wType = USB_EP_INTERRUPT; + ep_reg |= USB_EP_INTERRUPT; break; default: @@ -689,35 +599,35 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *p_endpoint_desc) TU_ASSERT(false); } - pcd_set_eptype(USB, ep_idx, wType); - pcd_set_ep_address(USB, ep_idx, tu_edpt_number(ep_addr)); - /* Create a packet memory buffer area. */ - pma_addr = dcd_pma_alloc(buffer_size, false); + uint16_t pma_addr = dcd_pma_alloc(packet_size, false); + btable_set_addr(ep_idx, dir == TUSB_DIR_IN ? BTABLE_BUF_TX : BTABLE_BUF_RX, pma_addr); + xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir); + xfer->max_packet_size = packet_size; + xfer->ep_idx = ep_idx; + + ep_change_status(&ep_reg, dir, EP_STAT_NAK); + ep_change_dtog(&ep_reg, dir, 0); + + // reserve other direction toggle bits if (dir == TUSB_DIR_IN) { - pcd_set_ep_tx_address(USB, ep_idx, pma_addr); - pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_NAK); - pcd_clear_tx_dtog(USB, ep_idx); + ep_reg &= ~(USB_EPRX_STAT | USB_EP_DTOG_RX); } else { - pcd_set_ep_rx_address(USB, ep_idx, pma_addr); - pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_NAK); - pcd_clear_rx_dtog(USB, ep_idx); + ep_reg &= ~(USB_EPTX_STAT | USB_EP_DTOG_TX); } - xfer_ctl_ptr(ep_addr)->max_packet_size = packet_size; - xfer_ctl_ptr(ep_addr)->ep_idx = ep_idx; + ep_write(ep_idx, ep_reg, true); return true; } -void dcd_edpt_close_all(uint8_t rhport) -{ - (void)rhport; +void dcd_edpt_close_all(uint8_t rhport) { + dcd_int_disable(rhport); for (uint32_t i = 1; i < FSDEV_EP_COUNT; i++) { // Reset endpoint - pcd_set_endpoint(USB, i, 0); + ep_write(i, 0, false); // Clear EP allocation status ep_alloc_status[i].ep_num = 0xFF; ep_alloc_status[i].ep_type = 0xFF; @@ -725,508 +635,340 @@ void dcd_edpt_close_all(uint8_t rhport) ep_alloc_status[i].allocated[1] = false; } + dcd_int_enable(rhport); + // Reset PMA allocation - ep_buf_ptr = DCD_STM32_BTABLE_BASE + 8 * CFG_TUD_ENDPPOINT_MAX + 2 * CFG_TUD_ENDPOINT0_SIZE; + ep_buf_ptr = FSDEV_BTABLE_BASE + 8 * CFG_TUD_ENDPPOINT_MAX + 2 * CFG_TUD_ENDPOINT0_SIZE; } -/** - * Close an endpoint. - * - * This function may be called with interrupts enabled or disabled. - * - * This also clears transfers in progress, should there be any. - */ -void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) -{ +bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { (void)rhport; - xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr); - uint8_t const ep_idx = xfer->ep_idx; + uint8_t const ep_num = tu_edpt_number(ep_addr); uint8_t const dir = tu_edpt_dir(ep_addr); - - if (dir == TUSB_DIR_IN) { - pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_DIS); - } else { - pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_DIS); - } -} - -bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) -{ - (void)rhport; - uint8_t const ep_idx = dcd_ep_alloc(ep_addr, TUSB_XFER_ISOCHRONOUS); - const uint16_t buffer_size = pcd_aligned_buffer_size(largest_packet_size); /* Create a packet memory buffer area. Enable double buffering for devices with 2048 bytes PMA, for smaller devices double buffering occupy too much space. */ #if FSDEV_PMA_SIZE > 1024u - uint32_t pma_addr = dcd_pma_alloc(buffer_size, true); + uint32_t pma_addr = dcd_pma_alloc(largest_packet_size, true); uint16_t pma_addr2 = pma_addr >> 16; #else - uint32_t pma_addr = dcd_pma_alloc(buffer_size, true); + uint32_t pma_addr = dcd_pma_alloc(largest_packet_size, false); uint16_t pma_addr2 = pma_addr; #endif - pcd_set_ep_tx_address(USB, ep_idx, pma_addr); - pcd_set_ep_rx_address(USB, ep_idx, pma_addr2); - pcd_set_eptype(USB, ep_idx, USB_EP_ISOCHRONOUS); + btable_set_addr(ep_idx, 0, pma_addr); + btable_set_addr(ep_idx, 1, pma_addr2); - xfer_ctl_ptr(ep_addr)->ep_idx = ep_idx; + xfer_ctl_t* xfer = xfer_ctl_ptr(ep_num, dir); + xfer->ep_idx = ep_idx; return true; } -bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const *p_endpoint_desc) -{ +bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const *desc_ep) { (void)rhport; - uint8_t const ep_addr = p_endpoint_desc->bEndpointAddress; - uint8_t const ep_idx = xfer_ctl_ptr(ep_addr)->ep_idx; - uint8_t const dir = tu_edpt_dir(ep_addr); - const uint16_t packet_size = tu_edpt_packet_size(p_endpoint_desc); + uint8_t const ep_addr = desc_ep->bEndpointAddress; + uint8_t const ep_num = tu_edpt_number(ep_addr); + tusb_dir_t const dir = tu_edpt_dir(ep_addr); + xfer_ctl_t* xfer = xfer_ctl_ptr(ep_num, dir); - pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_DIS); - pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_DIS); + uint8_t const ep_idx = xfer->ep_idx; - pcd_set_ep_address(USB, ep_idx, tu_edpt_number(ep_addr)); + xfer->max_packet_size = tu_edpt_packet_size(desc_ep); - pcd_clear_tx_dtog(USB, ep_idx); - pcd_clear_rx_dtog(USB, ep_idx); + uint32_t ep_reg = ep_read(ep_idx) & ~USB_EPREG_MASK; + ep_reg |= tu_edpt_number(ep_addr) | USB_EP_ISOCHRONOUS | USB_EP_CTR_TX | USB_EP_CTR_RX; + ep_change_status(&ep_reg, TUSB_DIR_IN, EP_STAT_DISABLED); + ep_change_status(&ep_reg, TUSB_DIR_OUT, EP_STAT_DISABLED); + ep_change_dtog(&ep_reg, dir, 0); + ep_change_dtog(&ep_reg, (tusb_dir_t)(1 - dir), 1); - if (dir == TUSB_DIR_IN) { - pcd_rx_dtog(USB, ep_idx); - } else { - pcd_tx_dtog(USB, ep_idx); - } - - xfer_ctl_ptr(ep_addr)->max_packet_size = packet_size; + ep_write(ep_idx, ep_reg, true); return true; } // Currently, single-buffered, and only 64 bytes at a time (max) +static void dcd_transmit_packet(xfer_ctl_t *xfer, uint16_t ep_ix) { + uint16_t len = tu_min16(xfer->total_len - xfer->queued_len, xfer->max_packet_size); + uint32_t ep_reg = ep_read(ep_ix) | USB_EP_CTR_TX | USB_EP_CTR_RX; // reserve CTR -static void dcd_transmit_packet(xfer_ctl_t *xfer, uint16_t ep_ix) -{ - uint16_t len = (uint16_t)(xfer->total_len - xfer->queued_len); - if (len > xfer->max_packet_size) { - len = xfer->max_packet_size; - } - - uint16_t ep_reg = pcd_get_endpoint(USB, ep_ix); - bool const is_iso = (ep_reg & USB_EP_TYPE_MASK) == USB_EP_ISOCHRONOUS; - uint16_t addr_ptr; + bool const is_iso = ep_is_iso(ep_reg); + uint8_t buf_id; if (is_iso) { - if (ep_reg & USB_EP_DTOG_TX) { - addr_ptr = pcd_get_ep_dbuf1_address(USB, ep_ix); - pcd_set_ep_tx_dbuf1_cnt(USB, ep_ix, len); - } else { - addr_ptr = pcd_get_ep_dbuf0_address(USB, ep_ix); - pcd_set_ep_tx_dbuf0_cnt(USB, ep_ix, len); - } + buf_id = (ep_reg & USB_EP_DTOG_TX) ? 1 : 0; } else { - addr_ptr = pcd_get_ep_tx_address(USB, ep_ix); - pcd_set_ep_tx_cnt(USB, ep_ix, len); + buf_id = BTABLE_BUF_TX; } + uint16_t addr_ptr = (uint16_t) btable_get_addr(ep_ix, buf_id); if (xfer->ff) { dcd_write_packet_memory_ff(xfer->ff, addr_ptr, len); } else { dcd_write_packet_memory(addr_ptr, &(xfer->buffer[xfer->queued_len]), len); } - xfer->queued_len = (uint16_t)(xfer->queued_len + len); + xfer->queued_len += len; + + btable_set_count(ep_ix, buf_id, len); + ep_change_status(&ep_reg, TUSB_DIR_IN, EP_STAT_VALID); - dcd_int_disable(0); - pcd_set_ep_tx_status(USB, ep_ix, USB_EP_TX_VALID); if (is_iso) { xfer->iso_in_sending = true; } - dcd_int_enable(0); + ep_reg &= USB_EPREG_MASK | EP_STAT_MASK(TUSB_DIR_IN); // only change TX Status, reserve other toggle bits + ep_write(ep_ix, ep_reg, true); } -static bool edpt_xfer(uint8_t rhport, uint8_t ep_addr) -{ - (void)rhport; +static bool edpt_xfer(uint8_t rhport, uint8_t ep_num, tusb_dir_t dir) { + (void) rhport; - xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr); + xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir); uint8_t const ep_idx = xfer->ep_idx; - uint8_t const dir = tu_edpt_dir(ep_addr); if (dir == TUSB_DIR_IN) { dcd_transmit_packet(xfer, ep_idx); } else { - // A setup token can occur immediately after an OUT STATUS packet so make sure we have a valid - // buffer for the control endpoint. - if (ep_idx == 0 && xfer->buffer == NULL) { - xfer->buffer = (uint8_t *)_setup_packet; - } + uint32_t ep_reg = ep_read(ep_idx) | USB_EP_CTR_TX | USB_EP_CTR_RX; // reserve CTR + ep_reg &= USB_EPREG_MASK | EP_STAT_MASK(dir); - uint32_t cnt = (uint32_t ) tu_min16(xfer->total_len, xfer->max_packet_size); - uint16_t ep_reg = pcd_get_endpoint(USB, ep_idx); + uint16_t cnt = tu_min16(xfer->total_len, xfer->max_packet_size); - if ((ep_reg & USB_EP_TYPE_MASK) == USB_EP_ISOCHRONOUS) { - pcd_set_ep_rx_dbuf0_cnt(USB, ep_idx, cnt); - pcd_set_ep_rx_dbuf1_cnt(USB, ep_idx, cnt); + if (ep_is_iso(ep_reg)) { + btable_set_rx_bufsize(ep_idx, 0, cnt); + btable_set_rx_bufsize(ep_idx, 1, cnt); } else { - pcd_set_ep_rx_cnt(USB, ep_idx, cnt); + btable_set_rx_bufsize(ep_idx, BTABLE_BUF_RX, cnt); } - pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_VALID); + ep_change_status(&ep_reg, dir, EP_STAT_VALID); + ep_write(ep_idx, ep_reg, true); } return true; } -bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes) -{ - xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr); +bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes) { + uint8_t const ep_num = tu_edpt_number(ep_addr); + tusb_dir_t const dir = tu_edpt_dir(ep_addr); + xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir); xfer->buffer = buffer; xfer->ff = NULL; xfer->total_len = total_bytes; xfer->queued_len = 0; - return edpt_xfer(rhport, ep_addr); + return edpt_xfer(rhport, ep_num, dir); } -bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t *ff, uint16_t total_bytes) -{ - xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr); +bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t *ff, uint16_t total_bytes) { + uint8_t const ep_num = tu_edpt_number(ep_addr); + tusb_dir_t const dir = tu_edpt_dir(ep_addr); + xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir); + xfer->buffer = NULL; xfer->ff = ff; xfer->total_len = total_bytes; xfer->queued_len = 0; - return edpt_xfer(rhport, ep_addr); + return edpt_xfer(rhport, ep_num, dir); } -void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) -{ +void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { (void)rhport; - - xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr); + uint8_t const ep_num = tu_edpt_number(ep_addr); + tusb_dir_t const dir = tu_edpt_dir(ep_addr); + xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir); uint8_t const ep_idx = xfer->ep_idx; - uint8_t const dir = tu_edpt_dir(ep_addr); - if (dir == TUSB_DIR_IN) { - pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_STALL); - } else { - pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_STALL); - } + uint32_t ep_reg = ep_read(ep_idx) | USB_EP_CTR_TX | USB_EP_CTR_RX; // reserve CTR bits + ep_reg &= USB_EPREG_MASK | EP_STAT_MASK(dir); + ep_change_status(&ep_reg, dir, EP_STAT_STALL); + + ep_write(ep_idx, ep_reg, true); } -void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) -{ +void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { (void)rhport; - xfer_ctl_t *xfer = xfer_ctl_ptr(ep_addr); + uint8_t const ep_num = tu_edpt_number(ep_addr); + tusb_dir_t const dir = tu_edpt_dir(ep_addr); + xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir); uint8_t const ep_idx = xfer->ep_idx; - uint8_t const dir = tu_edpt_dir(ep_addr); - if (dir == TUSB_DIR_IN) { // IN - if (pcd_get_eptype(USB, ep_idx) != USB_EP_ISOCHRONOUS) { - pcd_set_ep_tx_status(USB, ep_idx, USB_EP_TX_NAK); - } + uint32_t ep_reg = ep_read(ep_idx) | USB_EP_CTR_TX | USB_EP_CTR_RX; // reserve CTR bits + ep_reg &= USB_EPREG_MASK | EP_STAT_MASK(dir) | EP_DTOG_MASK(dir); - /* Reset to DATA0 if clearing stall condition. */ - pcd_clear_tx_dtog(USB, ep_idx); - } else { // OUT - if (pcd_get_eptype(USB, ep_idx) != USB_EP_ISOCHRONOUS) { - pcd_set_ep_rx_status(USB, ep_idx, USB_EP_RX_NAK); - } - /* Reset to DATA0 if clearing stall condition. */ - pcd_clear_rx_dtog(USB, ep_idx); + if (!ep_is_iso(ep_reg)) { + ep_change_status(&ep_reg, dir, EP_STAT_NAK); } + ep_change_dtog(&ep_reg, dir, 0); // Reset to DATA0 + ep_write(ep_idx, ep_reg, true); } -#ifdef FSDEV_BUS_32BIT -static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, uint16_t wNBytes) -{ - const uint8_t *srcVal = src; - volatile uint32_t *dst32 = (volatile uint32_t *)(USB_PMAADDR + dst); +//--------------------------------------------------------------------+ +// PMA read/write +//--------------------------------------------------------------------+ - for (uint32_t n = wNBytes / 4; n > 0; --n) { - *dst32++ = tu_unaligned_read32(srcVal); - srcVal += 4; - } +// Write to packet memory area (PMA) from user memory +// - Packet memory must be either strictly 16-bit or 32-bit depending on FSDEV_BUS_32BIT +// - Uses unaligned for RAM (since M0 cannot access unaligned address) +static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, uint16_t nbytes) { + if (nbytes == 0) return true; + uint32_t n_write = nbytes / FSDEV_BUS_SIZE; - wNBytes = wNBytes & 0x03; - if (wNBytes) { - uint32_t wrVal = *srcVal; - wNBytes--; + fsdev_pma_buf_t* pma_buf = PMA_BUF_AT(dst); + const uint8_t *src8 = src; - if (wNBytes) { - wrVal |= *++srcVal << 8; - wNBytes--; + while (n_write--) { + pma_buf->value = fsdevbus_unaligned_read(src8); + src8 += FSDEV_BUS_SIZE; + pma_buf++; + } - if (wNBytes) { - wrVal |= *++srcVal << 16; - } + // odd bytes e.g 1 for 16-bit or 1-3 for 32-bit + uint16_t odd = nbytes & (FSDEV_BUS_SIZE - 1); + if (odd) { + fsdev_bus_t temp = 0; + for(uint16_t i = 0; i < odd; i++) { + temp |= *src8++ << (i * 8); } - - *dst32 = wrVal; + pma_buf->value = temp; } return true; } -#else -// Packet buffer access can only be 8- or 16-bit. -/** - * @brief Copy a buffer from user memory area to packet memory area (PMA). - * This uses byte-access for user memory (so support non-aligned buffers) - * and 16-bit access for packet memory. - * @param dst, byte address in PMA; must be 16-bit aligned - * @param src pointer to user memory area. - * @param wPMABufAddr address into PMA. - * @param wNBytes no. of bytes to be copied. - * @retval None - */ -static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, uint16_t wNBytes) -{ - uint32_t n = (uint32_t)wNBytes >> 1U; - uint16_t temp1, temp2; - const uint8_t *srcVal; - // The GCC optimizer will combine access to 32-bit sizes if we let it. Force - // it volatile so that it won't do that. - __IO uint16_t *pdwVal; +// Read from packet memory area (PMA) to user memory. +// - Packet memory must be either strictly 16-bit or 32-bit depending on FSDEV_BUS_32BIT +// - Uses unaligned for RAM (since M0 cannot access unaligned address) +static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, uint16_t nbytes) { + if (nbytes == 0) return true; + uint32_t n_read = nbytes / FSDEV_BUS_SIZE; - srcVal = src; - pdwVal = &pma[FSDEV_PMA_STRIDE * (dst >> 1)]; + fsdev_pma_buf_t* pma_buf = PMA_BUF_AT(src); + uint8_t *dst8 = (uint8_t *)dst; - while (n--) { - temp1 = (uint16_t)*srcVal; - srcVal++; - temp2 = temp1 | ((uint16_t)(((uint16_t)(*srcVal)) << 8U)); - *pdwVal = temp2; - pdwVal += FSDEV_PMA_STRIDE; - srcVal++; + while (n_read--) { + fsdevbus_unaligned_write(dst8, (fsdev_bus_t ) pma_buf->value); + dst8 += FSDEV_BUS_SIZE; + pma_buf++; } - if (wNBytes) { - temp1 = (uint16_t) *srcVal; - *pdwVal = temp1; + // odd bytes e.g 1 for 16-bit or 1-3 for 32-bit + uint16_t odd = nbytes & (FSDEV_BUS_SIZE - 1); + if (odd) { + fsdev_bus_t temp = pma_buf->value; + while (odd--) { + *dst8++ = (uint8_t) (temp & 0xfful); + temp >>= 8; + } } return true; } -#endif -/** - * @brief Copy from FIFO to packet memory area (PMA). - * Uses byte-access of system memory and 16-bit access of packet memory - * @param wNBytes no. of bytes to be copied. - * @retval None - */ -static bool dcd_write_packet_memory_ff(tu_fifo_t *ff, uint16_t dst, uint16_t wNBytes) -{ +// Write to PMA from FIFO +static bool dcd_write_packet_memory_ff(tu_fifo_t *ff, uint16_t dst, uint16_t wNBytes) { + if (wNBytes == 0) return true; + // Since we copy from a ring buffer FIFO, a wrap might occur making it necessary to conduct two copies tu_fifo_buffer_info_t info; tu_fifo_get_read_info(ff, &info); - uint16_t cnt_lin = TU_MIN(wNBytes, info.len_lin); - uint16_t cnt_wrap = TU_MIN(wNBytes - cnt_lin, info.len_wrap); + uint16_t cnt_lin = tu_min16(wNBytes, info.len_lin); + uint16_t cnt_wrap = tu_min16(wNBytes - cnt_lin, info.len_wrap); + uint16_t const cnt_total = cnt_lin + cnt_wrap; // We want to read from the FIFO and write it into the PMA, if LIN part is ODD and has WRAPPED part, - // last lin byte will be combined with wrapped part - // To ensure PMA is always access aligned (dst aligned to 16 or 32 bit) -#ifdef FSDEV_BUS_32BIT - if ((cnt_lin & 0x03) && cnt_wrap) { - // Copy first linear part - dcd_write_packet_memory(dst, info.ptr_lin, cnt_lin & ~0x03); - dst += cnt_lin & ~0x03; - - // Copy last linear bytes & first wrapped bytes to buffer - uint32_t i; - uint8_t tmp[4]; - for (i = 0; i < (cnt_lin & 0x03); i++) { - tmp[i] = ((uint8_t *)info.ptr_lin)[(cnt_lin & ~0x03) + i]; - } - uint32_t wCnt = cnt_wrap; - for (; i < 4 && wCnt > 0; i++, wCnt--) { - tmp[i] = *(uint8_t *)info.ptr_wrap; - info.ptr_wrap = (uint8_t *)info.ptr_wrap + 1; - } - - // Write unaligned buffer - dcd_write_packet_memory(dst, &tmp, 4); - dst += 4; - - // Copy rest of wrapped byte - if (wCnt) - dcd_write_packet_memory(dst, info.ptr_wrap, wCnt); - } -#else - if ((cnt_lin & 0x01) && cnt_wrap) { - // Copy first linear part - dcd_write_packet_memory(dst, info.ptr_lin, cnt_lin & ~0x01); - dst += cnt_lin & ~0x01; + // last lin byte will be combined with wrapped part To ensure PMA is always access aligned + uint16_t lin_even = cnt_lin & ~(FSDEV_BUS_SIZE - 1); + uint16_t lin_odd = cnt_lin & (FSDEV_BUS_SIZE - 1); + uint8_t const *src8 = (uint8_t const*) info.ptr_lin; - // Copy last linear byte & first wrapped byte - uint16_t tmp = ((uint8_t *)info.ptr_lin)[cnt_lin - 1] | ((uint16_t)(((uint8_t *)info.ptr_wrap)[0]) << 8U); - dcd_write_packet_memory(dst, &tmp, 2); - dst += 2; + // write even linear part + dcd_write_packet_memory(dst, src8, lin_even); + dst += lin_even; + src8 += lin_even; - // Copy rest of wrapped byte - dcd_write_packet_memory(dst, ((uint8_t *)info.ptr_wrap) + 1, cnt_wrap - 1); - } -#endif - else { - // Copy linear part - dcd_write_packet_memory(dst, info.ptr_lin, cnt_lin); - dst += info.len_lin; - - if (info.len_wrap) { - // Copy wrapped byte - dcd_write_packet_memory(dst, info.ptr_wrap, cnt_wrap); + if (lin_odd == 0) { + src8 = (uint8_t const*) info.ptr_wrap; + } else { + // Combine last linear bytes + first wrapped bytes to form fsdev bus width data + fsdev_bus_t temp = 0; + uint16_t i; + for(i = 0; i < lin_odd; i++) { + temp |= *src8++ << (i * 8); } - } - tu_fifo_advance_read_pointer(ff, cnt_lin + cnt_wrap); - - return true; -} - -#ifdef FSDEV_BUS_32BIT -static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, uint16_t wNBytes) -{ - uint8_t *dstVal = dst; - volatile uint32_t *src32 = (volatile uint32_t *)(USB_PMAADDR + src); + src8 = (uint8_t const*) info.ptr_wrap; + for(; i < FSDEV_BUS_SIZE && cnt_wrap > 0; i++, cnt_wrap--) { + temp |= *src8++ << (i * 8); + } - for (uint32_t n = wNBytes / 4; n > 0; --n) { - tu_unaligned_write32(dstVal, *src32++); - dstVal += 4; + dcd_write_packet_memory(dst, &temp, FSDEV_BUS_SIZE); + dst += FSDEV_BUS_SIZE; } - wNBytes = wNBytes & 0x03; - if (wNBytes) { - uint32_t rdVal = *src32; - - *dstVal = tu_u32_byte0(rdVal); - wNBytes--; - - if (wNBytes) { - *++dstVal = tu_u32_byte1(rdVal); - wNBytes--; - - if (wNBytes) { - *++dstVal = tu_u32_byte2(rdVal); - } - } - } + // write the rest of the wrapped part + dcd_write_packet_memory(dst, src8, cnt_wrap); + tu_fifo_advance_read_pointer(ff, cnt_total); return true; } -#else -/** - * @brief Copy a buffer from packet memory area (PMA) to user memory area. - * Uses byte-access of system memory and 16-bit access of packet memory - * @param wNBytes no. of bytes to be copied. - * @retval None - */ -static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, uint16_t wNBytes) -{ - uint32_t n = (uint32_t)wNBytes >> 1U; - // The GCC optimizer will combine access to 32-bit sizes if we let it. Force - // it volatile so that it won't do that. - __IO const uint16_t *pdwVal; - uint32_t temp; - - pdwVal = &pma[FSDEV_PMA_STRIDE * (src >> 1)]; - uint8_t *dstVal = (uint8_t *)dst; - - while (n--) { - temp = *pdwVal; - pdwVal += FSDEV_PMA_STRIDE; - *dstVal++ = ((temp >> 0) & 0xFF); - *dstVal++ = ((temp >> 8) & 0xFF); - } - if (wNBytes & 0x01) { - temp = *pdwVal; - pdwVal += FSDEV_PMA_STRIDE; - *dstVal++ = ((temp >> 0) & 0xFF); - } - return true; -} -#endif +// Read from PMA to FIFO +static bool dcd_read_packet_memory_ff(tu_fifo_t *ff, uint16_t src, uint16_t wNBytes) { + if (wNBytes == 0) return true; -/** - * @brief Copy a buffer from user packet memory area (PMA) to FIFO. - * Uses byte-access of system memory and 16-bit access of packet memory - * @param wNBytes no. of bytes to be copied. - * @retval None - */ -static bool dcd_read_packet_memory_ff(tu_fifo_t *ff, uint16_t src, uint16_t wNBytes) -{ // Since we copy into a ring buffer FIFO, a wrap might occur making it necessary to conduct two copies // Check for first linear part tu_fifo_buffer_info_t info; tu_fifo_get_write_info(ff, &info); // We want to read from the FIFO - uint16_t cnt_lin = TU_MIN(wNBytes, info.len_lin); - uint16_t cnt_wrap = TU_MIN(wNBytes - cnt_lin, info.len_wrap); - - // We want to read from PMA and write it into the FIFO, if LIN part is ODD and has WRAPPED part, - // last lin byte will be combined with wrapped part - // To ensure PMA is always access aligned (src aligned to 16 or 32 bit) -#ifdef FSDEV_BUS_32BIT - if ((cnt_lin & 0x03) && cnt_wrap) { - // Copy first linear part - dcd_read_packet_memory(info.ptr_lin, src, cnt_lin & ~0x03); - src += cnt_lin & ~0x03; + uint16_t cnt_lin = tu_min16(wNBytes, info.len_lin); + uint16_t cnt_wrap = tu_min16(wNBytes - cnt_lin, info.len_wrap); + uint16_t cnt_total = cnt_lin + cnt_wrap; - // Copy last linear bytes & first wrapped bytes - uint8_t tmp[4]; - dcd_read_packet_memory(tmp, src, 4); - src += 4; - - uint32_t i; - for (i = 0; i < (cnt_lin & 0x03); i++) { - ((uint8_t *)info.ptr_lin)[(cnt_lin & ~0x03) + i] = tmp[i]; - } - uint32_t wCnt = cnt_wrap; - for (; i < 4 && wCnt > 0; i++, wCnt--) { - *(uint8_t *)info.ptr_wrap = tmp[i]; - info.ptr_wrap = (uint8_t *)info.ptr_wrap + 1; - } + // We want to read from the FIFO and write it into the PMA, if LIN part is ODD and has WRAPPED part, + // last lin byte will be combined with wrapped part To ensure PMA is always access aligned - // Copy rest of wrapped byte - if (wCnt) - dcd_read_packet_memory(info.ptr_wrap, src, wCnt); - } -#else - if ((cnt_lin & 0x01) && cnt_wrap) { - // Copy first linear part - dcd_read_packet_memory(info.ptr_lin, src, cnt_lin & ~0x01); - src += cnt_lin & ~0x01; + uint16_t lin_even = cnt_lin & ~(FSDEV_BUS_SIZE - 1); + uint16_t lin_odd = cnt_lin & (FSDEV_BUS_SIZE - 1); + uint8_t *dst8 = (uint8_t *) info.ptr_lin; - // Copy last linear byte & first wrapped byte - uint8_t tmp[2]; - dcd_read_packet_memory(tmp, src, 2); - src += 2; + // read even linear part + dcd_read_packet_memory(dst8, src, lin_even); + dst8 += lin_even; + src += lin_even; - ((uint8_t *)info.ptr_lin)[cnt_lin - 1] = tmp[0]; - ((uint8_t *)info.ptr_wrap)[0] = tmp[1]; + if (lin_odd == 0) { + dst8 = (uint8_t *) info.ptr_wrap; + } else { + // Combine last linear bytes + first wrapped bytes to form fsdev bus width data + fsdev_bus_t temp; + dcd_read_packet_memory(&temp, src, FSDEV_BUS_SIZE); + src += FSDEV_BUS_SIZE; - // Copy rest of wrapped byte - dcd_read_packet_memory(((uint8_t *)info.ptr_wrap) + 1, src, cnt_wrap - 1); - } -#endif - else { - // Copy linear part - dcd_read_packet_memory(info.ptr_lin, src, cnt_lin); - src += cnt_lin; + uint16_t i; + for (i = 0; i < lin_odd; i++) { + *dst8++ = (uint8_t) (temp & 0xfful); + temp >>= 8; + } - if (info.len_wrap) { - // Copy wrapped byte - dcd_read_packet_memory(info.ptr_wrap, src, cnt_wrap); + dst8 = (uint8_t *) info.ptr_wrap; + for (; i < FSDEV_BUS_SIZE && cnt_wrap > 0; i++, cnt_wrap--) { + *dst8++ = (uint8_t) (temp & 0xfful); + temp >>= 8; } } - tu_fifo_advance_write_pointer(ff, cnt_lin + cnt_wrap); + // read the rest of the wrapped part + dcd_read_packet_memory(dst8, src, cnt_wrap); + tu_fifo_advance_write_pointer(ff, cnt_total); return true; } diff --git a/src/portable/st/stm32_fsdev/fsdev_ch32.h b/src/portable/st/stm32_fsdev/fsdev_ch32.h index f63a80d56..518197c47 100644 --- a/src/portable/st/stm32_fsdev/fsdev_ch32.h +++ b/src/portable/st/stm32_fsdev/fsdev_ch32.h @@ -54,44 +54,8 @@ #endif #define FSDEV_PMA_SIZE (512u) - -// volatile 32-bit aligned -#define _va32 volatile TU_ATTR_ALIGNED(4) - -typedef struct { - _va32 uint16_t EP0R; // 00: USB Endpoint 0 register - _va32 uint16_t EP1R; // 04: USB Endpoint 1 register - _va32 uint16_t EP2R; // 08: USB Endpoint 2 register - _va32 uint16_t EP3R; // 0C: USB Endpoint 3 register - _va32 uint16_t EP4R; // 10: USB Endpoint 4 register - _va32 uint16_t EP5R; // 14: USB Endpoint 5 register - _va32 uint16_t EP6R; // 18: USB Endpoint 6 register - _va32 uint16_t EP7R; // 1C: USB Endpoint 7 register - _va32 uint16_t RESERVED7[16]; // Reserved - _va32 uint16_t CNTR; // 40: Control register - _va32 uint16_t ISTR; // 44: Interrupt status register - _va32 uint16_t FNR; // 48: Frame number register - _va32 uint16_t DADDR; // 4C: Device address register - _va32 uint16_t BTABLE; // 50: Buffer Table address register -} USB_TypeDef; - -TU_VERIFY_STATIC(sizeof(USB_TypeDef) == 0x54, "Size is not correct"); -TU_VERIFY_STATIC(offsetof(USB_TypeDef, CNTR) == 0x40, "Wrong offset"); - -#define USB_BASE (APB1PERIPH_BASE + 0x00005C00UL) /*!< USB_IP Peripheral Registers base address */ -#define USB_PMAADDR (APB1PERIPH_BASE + 0x00006000UL) /*!< USB_IP Packet Memory Area base address */ -#define USB ((USB_TypeDef *)USB_BASE) - -/******************************************************************************/ -/* */ -/* USB Device General registers */ -/* */ -/******************************************************************************/ -#define USB_CNTR (USB_BASE + 0x40U) /*!< Control register */ -#define USB_ISTR (USB_BASE + 0x44U) /*!< Interrupt status register */ -#define USB_FNR (USB_BASE + 0x48U) /*!< Frame number register */ -#define USB_DADDR (USB_BASE + 0x4CU) /*!< Device address register */ -#define USB_BTABLE (USB_BASE + 0x50U) /*!< Buffer Table address register */ +#define FSDEV_REG_BASE (APB1PERIPH_BASE + 0x00005C00UL) +#define FSDEV_PMA_BASE (APB1PERIPH_BASE + 0x00006000UL) /**************************** ISTR interrupt events *************************/ #define USB_ISTR_CTR ((uint16_t)0x8000U) /*!< Correct TRansfer (clear-only bit) */ diff --git a/src/portable/st/stm32_fsdev/fsdev_common.h b/src/portable/st/stm32_fsdev/fsdev_common.h deleted file mode 100644 index e8a6af8cb..000000000 --- a/src/portable/st/stm32_fsdev/fsdev_common.h +++ /dev/null @@ -1,371 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright(c) 2016 STMicroelectronics - * Copyright(c) N Conrad - * Copyright (c) 2024, hathach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - */ - -#ifndef TUSB_FSDEV_COMMON_H -#define TUSB_FSDEV_COMMON_H - -#ifdef __cplusplus - extern "C" { -#endif - -#include "stdint.h" - -// FSDEV_PMA_SIZE is PMA buffer size in bytes. -// On 512-byte devices, access with a stride of two words (use every other 16-bit address) -// On 1024-byte devices, access with a stride of one word (use every 16-bit address) - -// For purposes of accessing the packet -#if ((FSDEV_PMA_SIZE) == 512u) - #define FSDEV_PMA_STRIDE (2u) -#elif ((FSDEV_PMA_SIZE) == 1024u) - #define FSDEV_PMA_STRIDE (1u) -#endif - -// The fsdev_bus_t type can be used for both register and PMA access necessities -// For type-safety create a new macro for the volatile address of PMAADDR -// The compiler should warn us if we cast it to a non-volatile type? -#ifdef FSDEV_BUS_32BIT -typedef uint32_t fsdev_bus_t; -static volatile uint32_t * const pma32 = (volatile uint32_t*)USB_PMAADDR; - -#else -typedef uint16_t fsdev_bus_t; -// Volatile is also needed to prevent the optimizer from changing access to 32-bit (as 32-bit access is forbidden) -static volatile uint16_t * const pma = (volatile uint16_t*)USB_PMAADDR; - -TU_ATTR_ALWAYS_INLINE static inline volatile uint16_t * pcd_btable_word_ptr(USB_TypeDef * USBx, size_t x) { - size_t total_word_offset = (((USBx)->BTABLE)>>1) + x; - total_word_offset *= FSDEV_PMA_STRIDE; - return &(pma[total_word_offset]); -} - -TU_ATTR_ALWAYS_INLINE static inline volatile uint16_t* pcd_ep_tx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpIdx) { - return pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 1u); -} - -TU_ATTR_ALWAYS_INLINE static inline volatile uint16_t* pcd_ep_rx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpIdx) { - return pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 3u); -} -#endif - -/* Aligned buffer size according to hardware */ -TU_ATTR_ALWAYS_INLINE static inline uint16_t pcd_aligned_buffer_size(uint16_t size) { - /* The STM32 full speed USB peripheral supports only a limited set of - * buffer sizes given by the RX buffer entry format in the USB_BTABLE. */ - uint16_t blocksize = (size > 62) ? 32 : 2; - - // Round up while dividing requested size by blocksize - uint16_t numblocks = (size + blocksize - 1) / blocksize ; - - return numblocks * blocksize; -} - -TU_ATTR_ALWAYS_INLINE static inline void pcd_set_endpoint(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wRegValue) { -#ifdef FSDEV_BUS_32BIT - (void) USBx; - volatile uint32_t *reg = (volatile uint32_t *)(USB_DRD_BASE + bEpIdx*4); - *reg = wRegValue; -#else - volatile uint16_t *reg = (volatile uint16_t *)((&USBx->EP0R) + bEpIdx*2u); - *reg = (uint16_t)wRegValue; -#endif -} - -TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_endpoint(USB_TypeDef * USBx, uint32_t bEpIdx) { -#ifdef FSDEV_BUS_32BIT - (void) USBx; - volatile const uint32_t *reg = (volatile const uint32_t *)(USB_DRD_BASE + bEpIdx*4); -#else - volatile const uint16_t *reg = (volatile const uint16_t *)((&USBx->EP0R) + bEpIdx*2u); -#endif - return *reg; -} - -TU_ATTR_ALWAYS_INLINE static inline void pcd_set_eptype(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wType) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); - regVal &= (uint32_t)USB_EP_T_MASK; - regVal |= wType; - regVal |= USB_EP_CTR_RX | USB_EP_CTR_TX; // These clear on write0, so must set high - pcd_set_endpoint(USBx, bEpIdx, regVal); -} - -TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_eptype(USB_TypeDef * USBx, uint32_t bEpIdx) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); - regVal &= USB_EP_T_FIELD; - return regVal; -} - -/** - * @brief Clears bit CTR_RX / CTR_TX in the endpoint register. - * @param USBx USB peripheral instance register address. - * @param bEpIdx Endpoint Number. - * @retval None - */ -TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_rx_ep_ctr(USB_TypeDef * USBx, uint32_t bEpIdx) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); - regVal &= USB_EPREG_MASK; - regVal &= ~USB_EP_CTR_RX; - regVal |= USB_EP_CTR_TX; // preserve CTR_TX (clears on writing 0) - pcd_set_endpoint(USBx, bEpIdx, regVal); -} - -TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_tx_ep_ctr(USB_TypeDef * USBx, uint32_t bEpIdx) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); - regVal &= USB_EPREG_MASK; - regVal &= ~USB_EP_CTR_TX; - regVal |= USB_EP_CTR_RX; // preserve CTR_RX (clears on writing 0) - pcd_set_endpoint(USBx, bEpIdx,regVal); -} - -/** - * @brief gets counter of the tx buffer. - * @param USBx USB peripheral instance register address. - * @param bEpIdx Endpoint Number. - * @retval Counter value - */ -TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_tx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx) { -#ifdef FSDEV_BUS_32BIT - (void) USBx; - return (pma32[2*bEpIdx] & 0x03FF0000) >> 16; -#else - volatile const uint16_t *regPtr = pcd_ep_tx_cnt_ptr(USBx, bEpIdx); - return *regPtr & 0x3ffU; -#endif -} - -TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx) { -#ifdef FSDEV_BUS_32BIT - (void) USBx; - return (pma32[2*bEpIdx + 1] & 0x03FF0000) >> 16; -#else - volatile const uint16_t *regPtr = pcd_ep_rx_cnt_ptr(USBx, bEpIdx); - return *regPtr & 0x3ffU; -#endif -} - -#define pcd_get_ep_dbuf0_cnt pcd_get_ep_tx_cnt -#define pcd_get_ep_dbuf1_cnt pcd_get_ep_rx_cnt - -/** - * @brief Sets address in an endpoint register. - * @param USBx USB peripheral instance register address. - * @param bEpIdx Endpoint Number. - * @param bAddr Address. - * @retval None - */ -TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_address(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t bAddr) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); - regVal &= USB_EPREG_MASK; - regVal |= bAddr; - regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX; - pcd_set_endpoint(USBx, bEpIdx,regVal); -} - -TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_tx_address(USB_TypeDef * USBx, uint32_t bEpIdx) { -#ifdef FSDEV_BUS_32BIT - (void) USBx; - return pma32[2*bEpIdx] & 0x0000FFFFu ; -#else - return *pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 0u); -#endif -} - -TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_address(USB_TypeDef * USBx, uint32_t bEpIdx) { -#ifdef FSDEV_BUS_32BIT - (void) USBx; - return pma32[2*bEpIdx + 1] & 0x0000FFFFu; -#else - return *pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 2u); -#endif -} - -#define pcd_get_ep_dbuf0_address pcd_get_ep_tx_address -#define pcd_get_ep_dbuf1_address pcd_get_ep_rx_address - -TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_address(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t addr) { -#ifdef FSDEV_BUS_32BIT - (void) USBx; - pma32[2*bEpIdx] = (pma32[2*bEpIdx] & 0xFFFF0000u) | (addr & 0x0000FFFCu); -#else - *pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 0u) = addr; -#endif -} - -TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_address(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t addr) { -#ifdef FSDEV_BUS_32BIT - (void) USBx; - pma32[2*bEpIdx + 1] = (pma32[2*bEpIdx + 1] & 0xFFFF0000u) | (addr & 0x0000FFFCu); -#else - *pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 2u) = addr; -#endif -} - -#define pcd_set_ep_dbuf0_address pcd_set_ep_tx_address -#define pcd_set_ep_dbuf1_address pcd_set_ep_rx_address - -TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) { -#ifdef FSDEV_BUS_32BIT - (void) USBx; - pma32[2*bEpIdx] = (pma32[2*bEpIdx] & ~0x03FF0000u) | ((wCount & 0x3FFu) << 16); -#else - volatile uint16_t * reg = pcd_ep_tx_cnt_ptr(USBx, bEpIdx); - *reg = (uint16_t) (*reg & (uint16_t) ~0x3FFU) | (wCount & 0x3FFU); -#endif -} - -#define pcd_set_ep_tx_dbuf0_cnt pcd_set_ep_tx_cnt - -TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_dbuf1_cnt(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) { -#ifdef FSDEV_BUS_32BIT - (void) USBx; - pma32[2*bEpIdx + 1] = (pma32[2*bEpIdx + 1] & ~0x03FF0000u) | ((wCount & 0x3FFu) << 16); -#else - volatile uint16_t * reg = pcd_ep_rx_cnt_ptr(USBx, bEpIdx); - *reg = (uint16_t) (*reg & (uint16_t) ~0x3FFU) | (wCount & 0x3FFU); -#endif -} - -TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_blsize_num_blocks(USB_TypeDef * USBx, uint32_t rxtx_idx, - uint32_t blocksize, uint32_t numblocks) { - /* Encode into register. When BLSIZE==1, we need to subtract 1 block count */ -#ifdef FSDEV_BUS_32BIT - (void) USBx; - pma32[rxtx_idx] = (pma32[rxtx_idx] & 0x0000FFFFu) | (blocksize << 31) | ((numblocks - blocksize) << 26); -#else - volatile uint16_t *pdwReg = pcd_btable_word_ptr(USBx, rxtx_idx*2u + 1u); - *pdwReg = (blocksize << 15) | ((numblocks - blocksize) << 10); -#endif -} - -TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_bufsize(USB_TypeDef * USBx, uint32_t rxtx_idx, uint32_t wCount) { - wCount = pcd_aligned_buffer_size(wCount); - - /* We assume that the buffer size is already aligned to hardware requirements. */ - uint16_t blocksize = (wCount > 62) ? 1 : 0; - uint16_t numblocks = wCount / (blocksize ? 32 : 2); - - /* There should be no remainder in the above calculation */ - TU_ASSERT((wCount - (numblocks * (blocksize ? 32 : 2))) == 0, /**/); - - /* Encode into register. When BLSIZE==1, we need to subtract 1 block count */ - pcd_set_ep_blsize_num_blocks(USBx, rxtx_idx, blocksize, numblocks); -} - -TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_dbuf0_cnt(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) { - pcd_set_ep_bufsize(USBx, 2*bEpIdx, wCount); -} - -TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_cnt(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wCount) { - pcd_set_ep_bufsize(USBx, 2*bEpIdx + 1, wCount); -} - -#define pcd_set_ep_rx_dbuf1_cnt pcd_set_ep_rx_cnt - -/** - * @brief sets the status for tx transfer (bits STAT_TX[1:0]). - * @param USBx USB peripheral instance register address. - * @param bEpIdx Endpoint Number. - * @param wState new state - * @retval None - */ -TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_status(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wState) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); - regVal &= USB_EPTX_DTOGMASK; - regVal ^= wState; - regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX; - pcd_set_endpoint(USBx, bEpIdx, regVal); -} - -/** - * @brief sets the status for rx transfer (bits STAT_TX[1:0]) - * @param USBx USB peripheral instance register address. - * @param bEpIdx Endpoint Number. - * @param wState new state - * @retval None - */ - -TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_status(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wState) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); - regVal &= USB_EPRX_DTOGMASK; - regVal ^= wState; - regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX; - pcd_set_endpoint(USBx, bEpIdx, regVal); -} - -TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_status(USB_TypeDef * USBx, uint32_t bEpIdx) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); - return (regVal & USB_EPRX_STAT) >> (12u); -} - -TU_ATTR_ALWAYS_INLINE static inline void pcd_rx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); - regVal &= USB_EPREG_MASK; - regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX|USB_EP_DTOG_RX; - pcd_set_endpoint(USBx, bEpIdx, regVal); -} - -TU_ATTR_ALWAYS_INLINE static inline void pcd_tx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); - regVal &= USB_EPREG_MASK; - regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX|USB_EP_DTOG_TX; - pcd_set_endpoint(USBx, bEpIdx, regVal); -} - -TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_rx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); - if((regVal & USB_EP_DTOG_RX) != 0) { - pcd_rx_dtog(USBx,bEpIdx); - } -} - -TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_tx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); - if((regVal & USB_EP_DTOG_TX) != 0) { - pcd_tx_dtog(USBx,bEpIdx); - } -} - -TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_kind(USB_TypeDef * USBx, uint32_t bEpIdx) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); - regVal |= USB_EP_KIND; - regVal &= USB_EPREG_MASK; - regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX; - pcd_set_endpoint(USBx, bEpIdx, regVal); -} - -TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_ep_kind(USB_TypeDef * USBx, uint32_t bEpIdx) { - uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx); - regVal &= USB_EPKIND_MASK; - regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX; - pcd_set_endpoint(USBx, bEpIdx, regVal); -} - -#ifdef __cplusplus - } -#endif - -#endif diff --git a/src/portable/st/stm32_fsdev/fsdev_stm32.h b/src/portable/st/stm32_fsdev/fsdev_stm32.h index a8f61a35f..99fe8d55f 100644 --- a/src/portable/st/stm32_fsdev/fsdev_stm32.h +++ b/src/portable/st/stm32_fsdev/fsdev_stm32.h @@ -35,6 +35,7 @@ #if CFG_TUSB_MCU == OPT_MCU_STM32F0 #include "stm32f0xx.h" #define FSDEV_PMA_SIZE (1024u) + #define FSDEV_REG_BASE USB_BASE // F0x2 models are crystal-less // All have internal D+ pull-up // 070RB: 2 x 16 bits/word memory LPM Support, BCD Support @@ -81,12 +82,9 @@ #elif CFG_TUSB_MCU == OPT_MCU_STM32G0 #include "stm32g0xx.h" - #define FSDEV_BUS_32BIT #define FSDEV_PMA_SIZE (2048u) - #undef USB_PMAADDR - #define USB_PMAADDR USB_DRD_PMAADDR - #define USB_TypeDef USB_DRD_TypeDef - #define EP0R CHEP0R + #define USB USB_DRD_FS + #define USB_EP_CTR_RX USB_EP_VTRX #define USB_EP_CTR_TX USB_EP_VTTX #define USB_EP_T_FIELD USB_CHEP_UTYPE @@ -99,7 +97,6 @@ #define USB_EPRX_DTOG2 USB_CHEP_RX_DTOG2 #define USB_EPRX_STAT USB_CH_RX_VALID #define USB_EPKIND_MASK USB_EP_KIND_MASK - #define USB USB_DRD_FS #define USB_CNTR_FRES USB_CNTR_USBRST #define USB_CNTR_RESUME USB_CNTR_L2RES #define USB_ISTR_EP_ID USB_ISTR_IDN @@ -109,17 +106,9 @@ #elif CFG_TUSB_MCU == OPT_MCU_STM32H5 #include "stm32h5xx.h" - #define FSDEV_BUS_32BIT - - #if !defined(USB_DRD_BASE) && defined(USB_DRD_FS_BASE) - #define USB_DRD_BASE USB_DRD_FS_BASE - #endif - #define FSDEV_PMA_SIZE (2048u) - #undef USB_PMAADDR - #define USB_PMAADDR USB_DRD_PMAADDR - #define USB_TypeDef USB_DRD_TypeDef - #define EP0R CHEP0R + #define USB USB_DRD_FS + #define USB_EP_CTR_RX USB_EP_VTRX #define USB_EP_CTR_TX USB_EP_VTTX #define USB_EP_T_FIELD USB_CHEP_UTYPE @@ -132,7 +121,6 @@ #define USB_EPRX_DTOG2 USB_CHEP_RX_DTOG2 #define USB_EPRX_STAT USB_CH_RX_VALID #define USB_EPKIND_MASK USB_EP_KIND_MASK - #define USB USB_DRD_FS #define USB_CNTR_FRES USB_CNTR_USBRST #define USB_CNTR_RESUME USB_CNTR_L2RES #define USB_ISTR_EP_ID USB_ISTR_IDN @@ -143,9 +131,8 @@ #elif CFG_TUSB_MCU == OPT_MCU_STM32WB #include "stm32wbxx.h" #define FSDEV_PMA_SIZE (1024u) - /* ST provided header has incorrect value */ - #undef USB_PMAADDR - #define USB_PMAADDR USB1_PMAADDR + /* ST provided header has incorrect value of USB_PMAADDR */ + #define FSDEV_PMA_BASE USB1_PMAADDR #elif CFG_TUSB_MCU == OPT_MCU_STM32L4 #include "stm32l4xx.h" @@ -161,13 +148,9 @@ #elif CFG_TUSB_MCU == OPT_MCU_STM32U5 #include "stm32u5xx.h" - #define FSDEV_BUS_32BIT - #define FSDEV_PMA_SIZE (2048u) - #undef USB_PMAADDR - #define USB_PMAADDR USB_DRD_PMAADDR - #define USB_TypeDef USB_DRD_TypeDef - #define EP0R CHEP0R + #define USB USB_DRD_FS + #define USB_EP_CTR_RX USB_EP_VTRX #define USB_EP_CTR_TX USB_EP_VTTX #define USB_EP_T_FIELD USB_CHEP_UTYPE @@ -180,7 +163,6 @@ #define USB_EPRX_DTOG2 USB_CHEP_RX_DTOG2 #define USB_EPRX_STAT USB_CH_RX_VALID #define USB_EPKIND_MASK USB_EP_KIND_MASK - #define USB USB_DRD_FS #define USB_CNTR_FRES USB_CNTR_USBRST #define USB_CNTR_RESUME USB_CNTR_L2RES #define USB_ISTR_EP_ID USB_ISTR_IDN @@ -193,6 +175,31 @@ // This includes U0 #endif +//--------------------------------------------------------------------+ +// Register and PMA Base Address +//--------------------------------------------------------------------+ +#ifndef FSDEV_REG_BASE +#if defined(USB_BASE) + #define FSDEV_REG_BASE USB_BASE +#elif defined(USB_DRD_BASE) + #define FSDEV_REG_BASE USB_DRD_BASE +#elif defined(USB_DRD_FS_BASE) + #define FSDEV_REG_BASE USB_DRD_FS_BASE +#else + #error "FSDEV_REG_BASE not defined" +#endif +#endif + +#ifndef FSDEV_PMA_BASE +#if defined(USB_PMAADDR) + #define FSDEV_PMA_BASE USB_PMAADDR +#elif defined(USB_DRD_PMAADDR) + #define FSDEV_PMA_BASE USB_DRD_PMAADDR +#else + #error "FSDEV_PMA_BASE not defined" +#endif +#endif + // This checks if the device has "LPM" #if defined(USB_ISTR_L1REQ) #define USB_ISTR_L1REQ_FORCED (USB_ISTR_L1REQ) diff --git a/src/portable/st/stm32_fsdev/fsdev_type.h b/src/portable/st/stm32_fsdev/fsdev_type.h new file mode 100644 index 000000000..cf36576bb --- /dev/null +++ b/src/portable/st/stm32_fsdev/fsdev_type.h @@ -0,0 +1,307 @@ +/* + * The MIT License (MIT) + * + * Copyright(c) N Conrad + * Copyright(c) 2024, hathach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef TUSB_FSDEV_TYPE_H +#define TUSB_FSDEV_TYPE_H + +#ifdef __cplusplus + extern "C" { +#endif + +#include "stdint.h" + +// If sharing with CAN, one can set this to be non-zero to give CAN space where it wants it +// Both of these MUST be a multiple of 2, and are in byte units. +#ifndef FSDEV_BTABLE_BASE +#define FSDEV_BTABLE_BASE 0U +#endif + +TU_VERIFY_STATIC(FSDEV_BTABLE_BASE % 8 == 0, "BTABLE base must be aligned to 8 bytes"); + +// FSDEV_PMA_SIZE is PMA buffer size in bytes. +// - 512-byte devices, access with a stride of two words (use every other 16-bit address) +// - 1024-byte devices, access with a stride of one word (use every 16-bit address) +// - 2048-byte devices, access with 32-bit address + +// For purposes of accessing the packet +#if FSDEV_PMA_SIZE == 512 + // 1x16 bit / word access scheme + #define FSDEV_PMA_STRIDE 2 + #define pma_access_scheme TU_ATTR_ALIGNED(4) +#elif FSDEV_PMA_SIZE == 1024 + // 2x16 bit / word access scheme + #define FSDEV_PMA_STRIDE 1 + #define pma_access_scheme +#elif FSDEV_PMA_SIZE == 2048 + // 32 bit access scheme + #define FSDEV_BUS_32BIT + #define FSDEV_PMA_STRIDE 1 + #define pma_access_scheme +#endif + +// The fsdev_bus_t type can be used for both register and PMA access necessities +#ifdef FSDEV_BUS_32BIT + typedef uint32_t fsdev_bus_t; + #define fsdevbus_unaligned_read(_addr) tu_unaligned_read32(_addr) + #define fsdevbus_unaligned_write(_addr, _value) tu_unaligned_write32(_addr, _value) +#else + typedef uint16_t fsdev_bus_t; + #define fsdevbus_unaligned_read(_addr) tu_unaligned_read16(_addr) + #define fsdevbus_unaligned_write(_addr, _value) tu_unaligned_write16(_addr, _value) +#endif + +enum { + FSDEV_BUS_SIZE = sizeof(fsdev_bus_t), +}; + +//--------------------------------------------------------------------+ +// BTable Typedef +//--------------------------------------------------------------------+ +enum { + BTABLE_BUF_TX = 0, + BTABLE_BUF_RX = 1 +}; + +// hardware limit endpoint +#define FSDEV_EP_COUNT 8 + +// Buffer Table is located in Packet Memory Area (PMA) and therefore its address access is forced to either +// 16-bit or 32-bit depending on FSDEV_BUS_32BIT. +// 0: TX (IN), 1: RX (OUT) +typedef union { + // data is strictly 16-bit access (address could be 32-bit aligned) + struct { + volatile pma_access_scheme uint16_t addr; + volatile pma_access_scheme uint16_t count; + } ep16[FSDEV_EP_COUNT][2]; + + // strictly 32-bit access + struct { + volatile uint32_t count_addr; + } ep32[FSDEV_EP_COUNT][2]; +} fsdev_btable_t; + +TU_VERIFY_STATIC(sizeof(fsdev_btable_t) == FSDEV_EP_COUNT*8*FSDEV_PMA_STRIDE, "size is not correct"); +TU_VERIFY_STATIC(FSDEV_BTABLE_BASE + FSDEV_EP_COUNT*8 <= FSDEV_PMA_SIZE, "BTABLE does not fit in PMA RAM"); + +#define FSDEV_BTABLE ((volatile fsdev_btable_t*) (FSDEV_PMA_BASE + FSDEV_PMA_STRIDE*(FSDEV_BTABLE_BASE))) + +typedef struct { + volatile pma_access_scheme fsdev_bus_t value; +} fsdev_pma_buf_t; + +#define PMA_BUF_AT(_addr) ((fsdev_pma_buf_t*) (FSDEV_PMA_BASE + FSDEV_PMA_STRIDE*(_addr))) + +//--------------------------------------------------------------------+ +// Registers Typedef +//--------------------------------------------------------------------+ + +// volatile 32-bit aligned +#define _va32 volatile TU_ATTR_ALIGNED(4) + +typedef struct { + struct { + _va32 fsdev_bus_t reg; + }ep[FSDEV_EP_COUNT]; + + _va32 uint32_t RESERVED7[8]; // Reserved + _va32 fsdev_bus_t CNTR; // 40: Control register + _va32 fsdev_bus_t ISTR; // 44: Interrupt status register + _va32 fsdev_bus_t FNR; // 48: Frame number register + _va32 fsdev_bus_t DADDR; // 4C: Device address register + _va32 fsdev_bus_t BTABLE; // 50: Buffer Table address register (16-bit only) + _va32 fsdev_bus_t LPMCSR; // 54: LPM Control and Status Register (32-bit only) + _va32 fsdev_bus_t BCDR; // 58: Battery Charging Detector Register (32-bit only) +} fsdev_regs_t; + +TU_VERIFY_STATIC(offsetof(fsdev_regs_t, CNTR) == 0x40, "Wrong offset"); +TU_VERIFY_STATIC(sizeof(fsdev_regs_t) == 0x5C, "Size is not correct"); + +#define FSDEV_REG ((fsdev_regs_t*) FSDEV_REG_BASE) + + +#ifndef USB_EPTX_STAT +#define USB_EPTX_STAT 0x0030U +#endif + +#ifndef USB_EPRX_STAT +#define USB_EPRX_STAT 0x3000U +#endif + +#ifndef USB_EPTX_STAT_Pos +#define USB_EPTX_STAT_Pos 4u +#endif + +#ifndef USB_EP_DTOG_TX_Pos +#define USB_EP_DTOG_TX_Pos 6u +#endif + +#ifndef USB_EP_CTR_TX_Pos +#define USB_EP_CTR_TX_Pos 7u +#endif + +typedef enum { + EP_STAT_DISABLED = 0, + EP_STAT_STALL = 1, + EP_STAT_NAK = 2, + EP_STAT_VALID = 3 +}ep_stat_t; + +#define EP_STAT_MASK(_dir) (3u << (USB_EPTX_STAT_Pos + ((_dir) == TUSB_DIR_IN ? 0 : 8))) +#define EP_DTOG_MASK(_dir) (1u << (USB_EP_DTOG_TX_Pos + ((_dir) == TUSB_DIR_IN ? 0 : 8))) + +//--------------------------------------------------------------------+ +// Endpoint Helper +// - CTR is write 0 to clear +// - DTOG and STAT are write 1 to toggle +//--------------------------------------------------------------------+ + +TU_ATTR_ALWAYS_INLINE static inline uint32_t ep_read(uint32_t ep_id) { + return FSDEV_REG->ep[ep_id].reg; +} + +TU_ATTR_ALWAYS_INLINE static inline void ep_write(uint32_t ep_id, uint32_t value, bool need_exclusive) { + if (need_exclusive) { + dcd_int_disable(0); + } + + FSDEV_REG->ep[ep_id].reg = (fsdev_bus_t) value; + + if (need_exclusive) { + dcd_int_enable(0); + } +} + +TU_ATTR_ALWAYS_INLINE static inline void ep_write_clear_ctr(uint32_t ep_id, tusb_dir_t dir) { + uint32_t reg = FSDEV_REG->ep[ep_id].reg; + reg |= USB_EP_CTR_TX | USB_EP_CTR_RX; + reg &= USB_EPREG_MASK; + reg &= ~(1 << (USB_EP_CTR_TX_Pos + (dir == TUSB_DIR_IN ? 0 : 8))); + ep_write(ep_id, reg, false); +} + +TU_ATTR_ALWAYS_INLINE static inline void ep_change_status(uint32_t* reg, tusb_dir_t dir, ep_stat_t state) { + *reg ^= (state << (USB_EPTX_STAT_Pos + (dir == TUSB_DIR_IN ? 0 : 8))); +} + +TU_ATTR_ALWAYS_INLINE static inline void ep_change_dtog(uint32_t* reg, tusb_dir_t dir, uint8_t state) { + *reg ^= (state << (USB_EP_DTOG_TX_Pos + (dir == TUSB_DIR_IN ? 0 : 8))); +} + +TU_ATTR_ALWAYS_INLINE static inline bool ep_is_iso(uint32_t reg) { + return (reg & USB_EP_TYPE_MASK) == USB_EP_ISOCHRONOUS; +} + +//--------------------------------------------------------------------+ +// BTable Helper +//--------------------------------------------------------------------+ + +TU_ATTR_ALWAYS_INLINE static inline uint32_t btable_get_addr(uint32_t ep_id, uint8_t buf_id) { +#ifdef FSDEV_BUS_32BIT + return FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr & 0x0000FFFFu; +#else + return FSDEV_BTABLE->ep16[ep_id][buf_id].addr; +#endif +} + +TU_ATTR_ALWAYS_INLINE static inline void btable_set_addr(uint32_t ep_id, uint8_t buf_id, uint16_t addr) { +#ifdef FSDEV_BUS_32BIT + uint32_t count_addr = FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr; + count_addr = (count_addr & 0xFFFF0000u) | (addr & 0x0000FFFCu); + FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr = count_addr; +#else + FSDEV_BTABLE->ep16[ep_id][buf_id].addr = addr; +#endif +} + +TU_ATTR_ALWAYS_INLINE static inline uint16_t btable_get_count(uint32_t ep_id, uint8_t buf_id) { + uint16_t count; +#ifdef FSDEV_BUS_32BIT + count = (FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr >> 16); +#else + count = FSDEV_BTABLE->ep16[ep_id][buf_id].count; +#endif + return count & 0x3FFU; +} + +TU_ATTR_ALWAYS_INLINE static inline void btable_set_count(uint32_t ep_id, uint8_t buf_id, uint16_t byte_count) { +#ifdef FSDEV_BUS_32BIT + uint32_t count_addr = FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr; + count_addr = (count_addr & ~0x03FF0000u) | ((byte_count & 0x3FFu) << 16); + FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr = count_addr; +#else + uint16_t cnt = FSDEV_BTABLE->ep16[ep_id][buf_id].count; + cnt = (cnt & ~0x3FFU) | (byte_count & 0x3FFU); + FSDEV_BTABLE->ep16[ep_id][buf_id].count = cnt; +#endif +} + +/* Aligned buffer size according to hardware */ +TU_ATTR_ALWAYS_INLINE static inline uint16_t pma_align_buffer_size(uint16_t size, uint8_t* blsize, uint8_t* num_block) { + /* The STM32 full speed USB peripheral supports only a limited set of + * buffer sizes given by the RX buffer entry format in the USB_BTABLE. */ + uint16_t block_in_bytes; + if (size > 62) { + block_in_bytes = 32; + *blsize = 1; + *num_block = tu_div_ceil(size, 32); + } else { + block_in_bytes = 2; + *blsize = 0; + *num_block = tu_div_ceil(size, 2); + } + + return (*num_block) * block_in_bytes; +} + +TU_ATTR_ALWAYS_INLINE static inline void btable_set_rx_bufsize(uint32_t ep_id, uint8_t buf_id, uint16_t wCount) { + uint8_t blsize, num_block; + (void) pma_align_buffer_size(wCount, &blsize, &num_block); + + /* Encode into register. When BLSIZE==1, we need to subtract 1 block count */ + uint16_t bl_nb = (blsize << 15) | ((num_block - blsize) << 10); + if (bl_nb == 0) { + // zlp but 0 is invalid value, set blsize to 1 (32 bytes) + // Note: lower value can cause PMAOVR on setup with ch32v203 + bl_nb = 1 << 15; + } + +#ifdef FSDEV_BUS_32BIT + uint32_t count_addr = FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr; + count_addr = (bl_nb << 16) | (count_addr & 0x0000FFFFu); + FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr = count_addr; +#else + FSDEV_BTABLE->ep16[ep_id][buf_id].count = bl_nb; +#endif + +} + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c index 2871927be..12466e5ba 100644 --- a/src/portable/synopsys/dwc2/dcd_dwc2.c +++ b/src/portable/synopsys/dwc2/dcd_dwc2.c @@ -43,7 +43,7 @@ #if defined(TUP_USBIP_DWC2_STM32) #include "dwc2_stm32.h" -#elif TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3) +#elif defined(TUP_USBIP_DWC2_ESP32) #include "dwc2_esp32.h" #elif TU_CHECK_MCU(OPT_MCU_GD32VF103) #include "dwc2_gd32.h" @@ -732,12 +732,34 @@ void dcd_remote_wakeup(uint8_t rhport) { void dcd_connect(uint8_t rhport) { (void) rhport; dwc2_regs_t* dwc2 = DWC2_REG(rhport); + +#ifdef TUP_USBIP_DWC2_ESP32 + usb_wrap_otg_conf_reg_t conf = USB_WRAP.otg_conf; + conf.pad_pull_override = 0; + conf.dp_pullup = 0; + conf.dp_pulldown = 0; + conf.dm_pullup = 0; + conf.dm_pulldown = 0; + USB_WRAP.otg_conf = conf; +#endif + dwc2->dctl &= ~DCTL_SDIS; } void dcd_disconnect(uint8_t rhport) { (void) rhport; dwc2_regs_t* dwc2 = DWC2_REG(rhport); + +#ifdef TUP_USBIP_DWC2_ESP32 + usb_wrap_otg_conf_reg_t conf = USB_WRAP.otg_conf; + conf.pad_pull_override = 1; + conf.dp_pullup = 0; + conf.dp_pulldown = 1; + conf.dm_pullup = 0; + conf.dm_pulldown = 1; + USB_WRAP.otg_conf = conf; +#endif + dwc2->dctl |= DCTL_SDIS; } @@ -1299,25 +1321,13 @@ void dcd_int_handler(uint8_t rhport) { // } } -#if defined(TUP_USBIP_DWC2_TEST_MODE) && CFG_TUD_TEST_MODE - -bool dcd_check_test_mode_support(test_mode_t test_selector) { - // Check if test mode selector is unsupported - if (TEST_FORCE_ENABLE < test_selector || TEST_J > test_selector) { - return false; - } - - return true; -} - -void dcd_enter_test_mode(uint8_t rhport, test_mode_t test_selector) { - // Get port address... +#if CFG_TUD_TEST_MODE +void dcd_enter_test_mode(uint8_t rhport, tusb_feature_test_mode_t test_selector) { dwc2_regs_t* dwc2 = DWC2_REG(rhport); // Enable the test mode - dwc2->dctl = (dwc2->dctl & ~DCTL_TCTL_Msk) | (test_selector << DCTL_TCTL_Pos); + dwc2->dctl = (dwc2->dctl & ~DCTL_TCTL_Msk) | (((uint8_t) test_selector) << DCTL_TCTL_Pos); } - -#endif /* TUP_USBIP_DWC2_TEST_MODE && CFG_TUD_TEST_MODE */ +#endif #endif diff --git a/src/portable/synopsys/dwc2/dwc2_esp32.h b/src/portable/synopsys/dwc2/dwc2_esp32.h index 74b10aa9a..921cee29e 100644 --- a/src/portable/synopsys/dwc2/dwc2_esp32.h +++ b/src/portable/synopsys/dwc2/dwc2_esp32.h @@ -32,61 +32,53 @@ extern "C" { #endif +#include "freertos/task.h" + #include "esp_intr_alloc.h" #include "soc/periph_defs.h" -//#include "soc/usb_periph.h" -#include "freertos/task.h" +#include "soc/usb_wrap_struct.h" #define DWC2_REG_BASE 0x60080000UL #define DWC2_EP_MAX 7 #define DWC2_EP_IN_MAX 5 -static const dwc2_controller_t _dwc2_controller[] = -{ +static const dwc2_controller_t _dwc2_controller[] = { { .reg_base = DWC2_REG_BASE, .irqnum = 0, .ep_count = DWC2_EP_MAX, .ep_in_count = DWC2_EP_IN_MAX, .ep_fifo_size = 1024 } }; static intr_handle_t usb_ih; -static void dcd_int_handler_wrap(void* arg) -{ - (void) arg; +static void dcd_int_handler_wrap(void* arg) { + (void)arg; dcd_int_handler(0); } -TU_ATTR_ALWAYS_INLINE -static inline void dwc2_dcd_int_enable (uint8_t rhport) -{ - (void) rhport; +TU_ATTR_ALWAYS_INLINE static inline void dwc2_dcd_int_enable(uint8_t rhport) { + (void)rhport; esp_intr_alloc(ETS_USB_INTR_SOURCE, ESP_INTR_FLAG_LOWMED, dcd_int_handler_wrap, NULL, &usb_ih); } -TU_ATTR_ALWAYS_INLINE -static inline void dwc2_dcd_int_disable (uint8_t rhport) -{ - (void) rhport; +TU_ATTR_ALWAYS_INLINE static inline void dwc2_dcd_int_disable(uint8_t rhport) { + (void)rhport; esp_intr_free(usb_ih); } -static inline void dwc2_remote_wakeup_delay(void) -{ +TU_ATTR_ALWAYS_INLINE static inline void dwc2_remote_wakeup_delay(void) { vTaskDelay(pdMS_TO_TICKS(1)); } // MCU specific PHY init, called BEFORE core reset -static inline void dwc2_phy_init(dwc2_regs_t * dwc2, uint8_t hs_phy_type) -{ - (void) dwc2; - (void) hs_phy_type; +TU_ATTR_ALWAYS_INLINE static inline void dwc2_phy_init(dwc2_regs_t* dwc2, uint8_t hs_phy_type) { + (void)dwc2; + (void)hs_phy_type; // nothing to do } // MCU specific PHY update, it is called AFTER init() and core reset -static inline void dwc2_phy_update(dwc2_regs_t * dwc2, uint8_t hs_phy_type) -{ - (void) dwc2; - (void) hs_phy_type; +TU_ATTR_ALWAYS_INLINE static inline void dwc2_phy_update(dwc2_regs_t* dwc2, uint8_t hs_phy_type) { + (void)dwc2; + (void)hs_phy_type; // nothing to do } @@ -95,4 +87,4 @@ static inline void dwc2_phy_update(dwc2_regs_t * dwc2, uint8_t hs_phy_type) } #endif -#endif /* _DWC2_ESP32_H_ */ +#endif diff --git a/src/portable/template/dcd_template.c b/src/portable/template/dcd_template.c index 12d610bd6..25ee507c1 100644 --- a/src/portable/template/dcd_template.c +++ b/src/portable/template/dcd_template.c @@ -102,6 +102,22 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * ep_desc) return false; } +// Allocate packet buffer used by ISO endpoints +// Some MCU need manual packet buffer allocation, we allocate the largest size to avoid clustering +bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { + (void) rhport; + (void) ep_addr; + (void) largest_packet_size; + return false; +} + +// Configure and enable an ISO endpoint according to descriptor +bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * desc_ep) { + (void) rhport; + (void) desc_ep; + return false; +} + void dcd_edpt_close_all (uint8_t rhport) { (void) rhport; diff --git a/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c b/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c index 8005f5f7b..6b60bc657 100644 --- a/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c +++ b/src/portable/ti/msp430x5xx/dcd_msp430x5xx.c @@ -332,6 +332,11 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt) return true; } +void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) { + (void) rhport; (void) ep_addr; + // TODO implement dcd_edpt_close() +} + void dcd_edpt_close_all (uint8_t rhport) { (void) rhport; diff --git a/src/portable/valentyusb/eptri/dcd_eptri.c b/src/portable/valentyusb/eptri/dcd_eptri.c index 58628a8bb..8f40e3349 100644 --- a/src/portable/valentyusb/eptri/dcd_eptri.c +++ b/src/portable/valentyusb/eptri/dcd_eptri.c @@ -436,6 +436,11 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) return true; } +void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) { + (void) rhport; (void) ep_addr; + // TODO implement dcd_edpt_close() +} + void dcd_edpt_close_all (uint8_t rhport) { (void) rhport; diff --git a/src/tusb.c b/src/tusb.c index 0092267a1..860e8ac35 100644 --- a/src/tusb.c +++ b/src/tusb.c @@ -398,7 +398,7 @@ static void dump_str_line(uint8_t const* buf, uint16_t count) { tu_printf(" |"); // each line is 16 bytes for (uint16_t i = 0; i < count; i++) { - const char ch = buf[i]; + int ch = buf[i]; tu_printf("%c", isprint(ch) ? ch : '.'); } tu_printf("|\r\n"); diff --git a/src/tusb_option.h b/src/tusb_option.h index 8990cf92b..fb0209023 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -188,6 +188,12 @@ #define OPT_MCU_MCXN9 2300 ///< NXP MCX N9 Series #define OPT_MCU_MCXA15 2301 ///< NXP MCX A15 Series +// Analog Devices +#define OPT_MCU_MAX32690 2400 ///< ADI MAX32690 +#define OPT_MCU_MAX32666 2401 ///< ADI MAX32666/5 +#define OPT_MCU_MAX32650 2402 ///< ADI MAX32650/1/2 +#define OPT_MCU_MAX78002 2403 ///< ADI MAX78002 + // Check if configured MCU is one of listed // Apply _TU_CHECK_MCU with || as separator to list of input #define _TU_CHECK_MCU(_m) (CFG_TUSB_MCU == _m) @@ -381,7 +387,7 @@ #error "CFG_TUD_ENDPPOINT_MAX must be less than or equal to TUP_DCD_ENDPOINT_MAX" #endif -// USB 2.0 compliance test mode support +// USB 2.0 7.1.20: compliance test mode support #ifndef CFG_TUD_TEST_MODE #define CFG_TUD_TEST_MODE 0 #endif diff --git a/src/typec/tcd.h b/src/typec/tcd.h index 86499c951..bcbdab8ed 100644 --- a/src/typec/tcd.h +++ b/src/typec/tcd.h @@ -63,7 +63,7 @@ typedef struct TU_ATTR_PACKED { } xfer_complete; }; -} tcd_event_t;; +} tcd_event_t; //--------------------------------------------------------------------+ // |
