diff --git a/src/class/audio/audio.h b/src/class/audio/audio.h index 5e64549e..0027217c 100644 --- a/src/class/audio/audio.h +++ b/src/class/audio/audio.h @@ -497,11 +497,13 @@ typedef enum /// Isochronous End Point Attributes typedef enum { + TUSB_ISO_EP_ATT_NO_SYNC = 0x00, TUSB_ISO_EP_ATT_ASYNCHRONOUS = 0x04, TUSB_ISO_EP_ATT_ADAPTIVE = 0x08, TUSB_ISO_EP_ATT_SYNCHRONOUS = 0x0C, TUSB_ISO_EP_ATT_DATA = 0x00, ///< Data End Point - TUSB_ISO_EP_ATT_FB = 0x20, ///< Feedback End Point + TUSB_ISO_EP_ATT_EXPLICIT_FB = 0x10, ///< Feedback End Point + TUSB_ISO_EP_ATT_IMPLICIT_FB = 0x20, ///< Data endpoint that also serves as an implicit feedback } tusb_iso_ep_attribute_t; /// Audio Class-Control Values UAC2 diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index ebb8434c..1b9cfe13 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -46,8 +46,22 @@ //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ + +#if CFG_TUD_AUDIO_EPSIZE_IN && CFG_TUD_AUDIO_TX_FIFO_SIZE +#ifndef CFG_TUD_AUDIO_TX_FIFO_COUNT +#define CFG_TUD_AUDIO_TX_FIFO_COUNT CFG_TUD_AUDIO_N_CHANNELS_TX +#endif +#endif + +#if CFG_TUD_AUDIO_EPSIZE_OUT && CFG_TUD_AUDIO_RX_FIFO_SIZE +#ifndef CFG_TUD_AUDIO_RX_FIFO_COUNT +#define CFG_TUD_AUDIO_RX_FIFO_COUNT CFG_TUD_AUDIO_N_CHANNELS_RX +#endif +#endif + typedef struct { + uint8_t rhport; uint8_t const * p_desc; // Pointer pointing to Standard AC Interface Descriptor(4.7.1) - Audio Control descriptor defining audio function #if CFG_TUD_AUDIO_EPSIZE_IN @@ -80,18 +94,18 @@ typedef struct // FIFO #if CFG_TUD_AUDIO_EPSIZE_IN && CFG_TUD_AUDIO_TX_FIFO_SIZE - tu_fifo_t tx_ff[CFG_TUD_AUDIO_N_CHANNELS_TX]; - CFG_TUSB_MEM_ALIGN uint8_t tx_ff_buf[CFG_TUD_AUDIO_N_CHANNELS_TX][CFG_TUD_AUDIO_TX_FIFO_SIZE * CFG_TUD_AUDIO_TX_ITEMSIZE]; + tu_fifo_t tx_ff[CFG_TUD_AUDIO_TX_FIFO_COUNT]; + CFG_TUSB_MEM_ALIGN uint8_t tx_ff_buf[CFG_TUD_AUDIO_TX_FIFO_COUNT][CFG_TUD_AUDIO_TX_FIFO_SIZE]; #if CFG_FIFO_MUTEX - osal_mutex_def_t tx_ff_mutex[CFG_TUD_AUDIO_N_CHANNELS_TX]; + osal_mutex_def_t tx_ff_mutex[CFG_TUD_AUDIO_TX_FIFO_COUNT]; #endif #endif #if CFG_TUD_AUDIO_EPSIZE_OUT && CFG_TUD_AUDIO_RX_FIFO_SIZE - tu_fifo_t rx_ff[CFG_TUD_AUDIO_N_CHANNELS_RX]; - CFG_TUSB_MEM_ALIGN uint8_t rx_ff_buf[CFG_TUD_AUDIO_N_CHANNELS_RX][CFG_TUD_AUDIO_RX_FIFO_SIZE * CFG_TUD_AUDIO_RX_ITEMSIZE]; + tu_fifo_t rx_ff[CFG_TUD_AUDIO_RX_FIFO_COUNT]; + CFG_TUSB_MEM_ALIGN uint8_t rx_ff_buf[CFG_TUD_AUDIO_RX_FIFO_COUNT][CFG_TUD_AUDIO_RX_FIFO_SIZE]; #if CFG_FIFO_MUTEX - osal_mutex_def_t rx_ff_mutex[CFG_TUD_AUDIO_N_CHANNELS_RX]; + osal_mutex_def_t rx_ff_mutex[CFG_TUD_AUDIO_RX_FIFO_COUNT]; #endif #endif @@ -107,10 +121,9 @@ typedef struct #if CFG_TUD_AUDIO_EPSIZE_OUT CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_AUDIO_EPSIZE_OUT]; // Bigger makes no sense for isochronous EP's (but technically possible here) - // TODO: required? - //#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - // uint16_t fb_val; // Feedback value for asynchronous mode! - //#endif +#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + uint32_t fb_val; // Feedback value for asynchronous mode (in 16.16 format). +#endif #endif @@ -134,7 +147,7 @@ CFG_TUSB_MEM_SECTION audiod_interface_t _audiod_itf[CFG_TUD_AUDIO]; extern const uint16_t tud_audio_desc_lengths[]; #if CFG_TUD_AUDIO_EPSIZE_OUT -static audio_rx_done_type_I_pcm_ff_cb(uint8_t rhport, audiod_interface_t* audio, uint8_t const* buffer, uint32_t bufsize); +static bool audio_rx_done_type_I_pcm_ff_cb(uint8_t rhport, audiod_interface_t* audio, uint8_t * buffer, uint16_t bufsize); #endif #if CFG_TUD_AUDIO_EPSIZE_IN @@ -189,7 +202,7 @@ bool tud_audio_n_mounted(uint8_t itf) //--------------------------------------------------------------------+ #if CFG_TUD_AUDIO_EPSIZE_OUT && CFG_TUD_AUDIO_RX_FIFO_SIZE - +#if CFG_TUD_AUDIO_RX_FIFO_COUNT > 1 uint16_t tud_audio_n_available(uint8_t itf, uint8_t channelId) { TU_VERIFY(channelId < CFG_TUD_AUDIO_N_CHANNELS_RX); @@ -204,10 +217,25 @@ uint16_t tud_audio_n_read(uint8_t itf, uint8_t channelId, void* buffer, uint16_t void tud_audio_n_read_flush (uint8_t itf, uint8_t channelId) { - TU_VERIFY(channelId < CFG_TUD_AUDIO_N_CHANNELS_RX); + TU_VERIFY(channelId < CFG_TUD_AUDIO_N_CHANNELS_RX, ); tu_fifo_clear(&_audiod_itf[itf].rx_ff[channelId]); } +#else +uint16_t tud_audio_n_available(uint8_t itf) +{ + return tu_fifo_count(&_audiod_itf[itf].rx_ff[0]); +} +uint16_t tud_audio_n_read(uint8_t itf, void* buffer, uint16_t bufsize) +{ + return tu_fifo_read_n(&_audiod_itf[itf].rx_ff[0], buffer, bufsize); +} + +void tud_audio_n_read_flush (uint8_t itf) +{ + tu_fifo_clear(&_audiod_itf[itf].rx_ff[0]); +} +#endif #endif #if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN @@ -282,12 +310,14 @@ static bool audio_rx_done_cb(uint8_t rhport, audiod_interface_t* audio, uint8_t* // The following functions are used in case CFG_TUD_AUDIO_RX_FIFO_SIZE != 0 #if CFG_TUD_AUDIO_RX_FIFO_SIZE +#if CFG_TUD_AUDIO_RX_FIFO_COUNT > 1 static bool audio_rx_done_type_I_pcm_ff_cb(uint8_t rhport, audiod_interface_t* audio, uint8_t * buffer, uint16_t bufsize) { (void) rhport; // We expect to get a multiple of CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX * CFG_TUD_AUDIO_N_CHANNELS_RX per channel - if (bufsize % CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX*CFG_TUD_AUDIO_N_CHANNELS_RX != 0) { + if (bufsize % (CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX * CFG_TUD_AUDIO_N_CHANNELS_RX) != 0) + { return false; } @@ -316,7 +346,23 @@ static bool audio_rx_done_type_I_pcm_ff_cb(uint8_t rhport, audiod_interface_t* a chId = 0; } } -} } + return true; +} +#else +static bool audio_rx_done_type_I_pcm_ff_cb(uint8_t rhport, audiod_interface_t *audio, uint8_t *buffer, uint16_t bufsize) +{ + (void) rhport; + + // We expect to get a multiple of CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX * CFG_TUD_AUDIO_N_CHANNELS_RX per channel + if (bufsize % (CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX * CFG_TUD_AUDIO_N_CHANNELS_RX) != 0) + { + return false; + } + + tu_fifo_write_n(&audio->rx_ff[0], buffer, bufsize); + return true; +} +#endif // CFG_TUD_AUDIO_RX_FIFO_COUNT > 1 #endif //CFG_TUD_AUDIO_RX_FIFO_SIZE //--------------------------------------------------------------------+ @@ -334,9 +380,9 @@ static bool audio_rx_done_type_I_pcm_ff_cb(uint8_t rhport, audiod_interface_t* a * \param[in] len: # of array elements to copy * \return Number of bytes actually written */ - +#if CFG_TUD_AUDIO_EPSIZE_IN +#if !CFG_TUD_AUDIO_TX_FIFO_SIZE /* This function is intended for later use once EP buffers (at least for ISO EPs) are implemented as ring buffers -#if CFG_TUD_AUDIO_EPSIZE_IN && !CFG_TUD_AUDIO_TX_FIFO_SIZE uint16_t tud_audio_n_write_ep_in_buffer(uint8_t itf, const void * data, uint16_t len) { audiod_interface_t* audio = &_audiod_itf[itf]; @@ -363,11 +409,23 @@ uint16_t tud_audio_n_write_ep_in_buffer(uint8_t itf, const void * data, uint16_t // Return number of bytes written return len; } -#endif - */ -#if CFG_TUD_AUDIO_EPSIZE_IN && CFG_TUD_AUDIO_TX_FIFO_SIZE +#else + +#if CFG_TUD_AUDIO_TX_FIFO_COUNT == 1 +uint16_t tud_audio_n_write(uint8_t itf, void const* data, uint16_t len) +{ + { + audiod_interface_t* audio = &_audiod_itf[itf]; + if (audio->p_desc == NULL) + { + return 0; + } + return tu_fifo_write_n(&audio->tx_ff[0], data, len); + } +} +#else uint16_t tud_audio_n_write(uint8_t itf, uint8_t channelId, const void * data, uint16_t len) { audiod_interface_t* audio = &_audiod_itf[itf]; @@ -379,6 +437,23 @@ uint16_t tud_audio_n_write(uint8_t itf, uint8_t channelId, const void * data, ui } #endif +static bool audiod_tx_done_cb(uint8_t rhport, audiod_interface_t* audio, uint16_t * n_bytes_copied); + +uint16_t tud_audio_n_write_flush(uint8_t itf) +{ + audiod_interface_t *audio = &_audiod_itf[itf]; + if (audio->p_desc == NULL) { + return 0; + } + + uint16_t n_bytes_copied; + TU_VERIFY(audiod_tx_done_cb(audio->rhport, audio, &n_bytes_copied)); + return n_bytes_copied; +} + +#endif +#endif + #if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN > 0 uint32_t tud_audio_int_ctr_n_write(uint8_t itf, uint8_t const* buffer, uint32_t bufsize) { @@ -475,6 +550,7 @@ static bool audiod_tx_done_cb(uint8_t rhport, audiod_interface_t* audio, uint16_ #endif //CFG_TUD_AUDIO_EPSIZE_IN #if CFG_TUD_AUDIO_TX_FIFO_SIZE +#if CFG_TUD_AUDIO_TX_FIFO_COUNT > 1 || (CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX != CFG_TUD_AUDIO_TX_ITEMSIZE) static bool audiod_tx_done_type_I_pcm_ff_cb(uint8_t rhport, audiod_interface_t* audio) { // We encode directly into IN EP's buffer - abort if previous transfer not complete @@ -482,15 +558,15 @@ static bool audiod_tx_done_type_I_pcm_ff_cb(uint8_t rhport, audiod_interface_t* // Determine amount of samples uint16_t const nEndpointSampleCapacity = CFG_TUD_AUDIO_EPSIZE_IN / CFG_TUD_AUDIO_N_CHANNELS_TX / CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX; - uint16_t nSamplesPerChannelToSend = tu_fifo_count(&audio->tx_ff[0]); + uint16_t nSamplesPerChannelToSend = tu_fifo_count(&audio->tx_ff[0]) / CFG_TUD_AUDIO_TX_ITEMSIZE; uint16_t nBytesToSend; uint8_t cntChannel; for (cntChannel = 1; cntChannel < CFG_TUD_AUDIO_N_CHANNELS_TX; cntChannel++) { - if (audio->tx_ff[cntChannel].count < nSamplesPerChannelToSend) + if (audio->tx_ff[cntChannel].count / CFG_TUD_AUDIO_TX_ITEMSIZE < nSamplesPerChannelToSend) { - nSamplesPerChannelToSend = audio->tx_ff[cntChannel].count; + nSamplesPerChannelToSend = audio->tx_ff[cntChannel].count * CFG_TUD_AUDIO_TX_ITEMSIZE; } } @@ -522,7 +598,7 @@ static bool audiod_tx_done_type_I_pcm_ff_cb(uint8_t rhport, audiod_interface_t* for (cntChannel = 0; cntChannel < CFG_TUD_AUDIO_N_CHANNELS_TX; cntChannel++) { // Get sample from buffer - tu_fifo_read(&audio->tx_ff[cntChannel], &sample); + tu_fifo_read_n(&audio->tx_ff[cntChannel], &sample, CFG_TUD_AUDIO_TX_ITEMSIZE); // Put it into EP's buffer - Let alignment problems be handled by memcpy memcpy(pBuff, &sample, CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX); @@ -537,23 +613,80 @@ static bool audiod_tx_done_type_I_pcm_ff_cb(uint8_t rhport, audiod_interface_t* return true; } +#else +static bool audiod_tx_done_type_I_pcm_ff_cb(uint8_t rhport, audiod_interface_t* audio) +{ + // We encode directly into IN EP's buffer - abort if previous transfer not complete + TU_VERIFY(!usbd_edpt_busy(rhport, audio->ep_in)); + + // Determine amount of samples + uint16_t nByteCount = tu_fifo_count(&audio->tx_ff[0]); + + nByteCount = tu_min16(nByteCount, CFG_TUD_AUDIO_EPSIZE_IN); + + // Check if there is enough + if (nByteCount == 0) + { + return true; + } + + nByteCount = tu_fifo_read_n(&audio->tx_ff[0], audio->epin_buf, nByteCount); + audio->epin_buf_cnt = nByteCount; + + return true; +} +#endif // CFG_TUD_AUDIO_TX_FIFO_COUNT > 1 || (CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX != CFG_TUD_AUDIO_TX_ITEMSIZE) + #endif //CFG_TUD_AUDIO_TX_FIFO_SIZE // This function is called once a transmit of an feedback packet was successfully completed. Here, we get the next feedback value to be sent #if CFG_TUD_AUDIO_EPSIZE_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP -static uint16_t audio_fb_done_cb(uint8_t rhport, audiod_interface_t* audio) +static bool audio_fb_send(uint8_t rhport, audiod_interface_t *audio) { - (void) rhport; - (void) audio; + uint8_t fb[4]; + uint16_t len; - // Here we need to return the feedback value -#error RETURN YOUR FEEDBACK VALUE HERE! + if (audio->fb_val == 0) + { + len = 0; + return true; + } + else + { + len = 4; + // Here we need to return the feedback value + if (rhport == 0) + { + // For FS format is 10.14 + fb[0] = (audio->fb_val >> 2) & 0xFF; + fb[1] = (audio->fb_val >> 10) & 0xFF; + fb[2] = (audio->fb_val >> 18) & 0xFF; + // 4th byte is needed to work correctly with MS Windows + fb[3] = 0; + } + else + { + // For HS format is 16.16 + fb[0] = (audio->fb_val >> 0) & 0xFF; + fb[1] = (audio->fb_val >> 8) & 0xFF; + fb[2] = (audio->fb_val >> 16) & 0xFF; + fb[3] = (audio->fb_val >> 24) & 0xFF; + } + return usbd_edpt_xfer(rhport, audio->ep_fb, fb, len); + } - if (tud_audio_fb_done_cb) TU_VERIFY(tud_audio_fb_done_cb(rhport)); - return 0; } +//static uint16_t audio_fb_done_cb(uint8_t rhport, audiod_interface_t* audio) +//{ +// (void) rhport; +// (void) audio; +// +// if (tud_audio_fb_done_cb) TU_VERIFY(tud_audio_fb_done_cb(rhport)); +// return 0; +//} + #endif // This function is called once a transmit of an interrupt control packet was successfully completed. Here, we get the remaining bytes to send @@ -586,7 +719,6 @@ static bool audio_int_ctr_done_cb(uint8_t rhport, audiod_interface_t* audio, uin //--------------------------------------------------------------------+ void audiod_init(void) { - uint8_t cnt; tu_memclr(_audiod_itf, sizeof(_audiod_itf)); for(uint8_t i=0; itx_ff[cnt], &audio->tx_ff_buf[cnt], CFG_TUD_AUDIO_TX_FIFO_SIZE, CFG_TUD_AUDIO_TX_ITEMSIZE, true); + tu_fifo_config(&audio->tx_ff[cnt], &audio->tx_ff_buf[cnt], CFG_TUD_AUDIO_TX_FIFO_SIZE, 1, true); #if CFG_FIFO_MUTEX tu_fifo_config_mutex(&audio->tx_ff[cnt], osal_mutex_create(&audio->tx_ff_mutex[cnt])); #endif @@ -605,9 +737,9 @@ void audiod_init(void) #endif #if CFG_TUD_AUDIO_EPSIZE_OUT && CFG_TUD_AUDIO_RX_FIFO_SIZE - for (cnt = 0; cnt < CFG_TUD_AUDIO_N_CHANNELS_RX; cnt++) + for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_RX_FIFO_COUNT; cnt++) { - tu_fifo_config(&audio->rx_ff[cnt], &audio->rx_ff_buf[cnt], CFG_TUD_AUDIO_RX_FIFO_SIZE, CFG_TUD_AUDIO_RX_ITEMSIZE, true); + tu_fifo_config(&audio->rx_ff[cnt], &audio->rx_ff_buf[cnt], CFG_TUD_AUDIO_RX_FIFO_SIZE, 1, true); #if CFG_FIFO_MUTEX tu_fifo_config_mutex(&audio->rx_ff[cnt], osal_mutex_create(&audio->rx_ff_mutex[cnt])); #endif @@ -632,16 +764,15 @@ void audiod_reset(uint8_t rhport) audiod_interface_t* audio = &_audiod_itf[i]; tu_memclr(audio, ITF_MEM_RESET_SIZE); - uint8_t cnt; #if CFG_TUD_AUDIO_EPSIZE_IN && CFG_TUD_AUDIO_TX_FIFO_SIZE - for (cnt = 0; cnt < CFG_TUD_AUDIO_N_CHANNELS_TX; cnt++) + for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_TX_FIFO_COUNT; cnt++) { tu_fifo_clear(&audio->tx_ff[cnt]); } #endif #if CFG_TUD_AUDIO_EPSIZE_OUT && CFG_TUD_AUDIO_RX_FIFO_SIZE - for (cnt = 0; cnt < CFG_TUD_AUDIO_N_CHANNELS_RX; cnt++) + for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_RX_FIFO_COUNT; cnt++) { tu_fifo_clear(&audio->rx_ff[cnt]); } @@ -673,6 +804,7 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin if (!_audiod_itf[i].p_desc) { _audiod_itf[i].p_desc = (uint8_t const *)itf_desc; // Save pointer to AC descriptor which is by specification always the first one + _audiod_itf[i].rhport = rhport; break; } } @@ -818,7 +950,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * } #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && ((tusb_desc_endpoint_t const *) p_desc)->bmAttributes.usage == 0x10) // Check if usage is implicit data feedback + if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && ((tusb_desc_endpoint_t const *) p_desc)->bmAttributes.usage == 1) // Check if usage is explicit data feedback { _audiod_itf[idxDriver].ep_fb = ep_addr; @@ -1115,13 +1247,9 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3 // Transmission of feedback EP finished if (_audiod_itf[idxDriver].ep_fb == ep_addr) { - if (!audio_fb_done_cb(rhport, &_audiod_itf[idxDriver])) - { - // Load with ZLP - return usbd_edpt_xfer(rhport, ep_addr, NULL, 0); - } + if (tud_audio_fb_done_cb) TU_VERIFY(tud_audio_fb_done_cb(rhport)); - return true; + return audio_fb_send(rhport, &_audiod_itf[idxDriver]); } #endif #endif @@ -1303,4 +1431,16 @@ static bool audiod_verify_ep_exists(uint8_t ep, uint8_t *idxDriver) return false; } +#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP +bool tud_audio_fb_set(uint8_t rhport, uint32_t feedback) +{ + audiod_interface_t *audio = &_audiod_itf[0]; + + audio->fb_val = feedback; + TU_VERIFY(!usbd_edpt_busy(rhport, audio->ep_fb), true); + + return audio_fb_send(rhport, audio); +} +#endif + #endif //TUSB_OPT_DEVICE_ENABLED && CFG_TUD_AUDIO diff --git a/src/class/audio/audio_device.h b/src/class/audio/audio_device.h index 11f444da..f4029a84 100644 --- a/src/class/audio/audio_device.h +++ b/src/class/audio/audio_device.h @@ -119,6 +119,7 @@ #define CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX 1 #endif +#ifndef CFG_TUD_AUDIO_TX_ITEMSIZE #if CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX == 1 #define CFG_TUD_AUDIO_TX_ITEMSIZE 1 #elif CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX == 2 @@ -126,6 +127,11 @@ #else #define CFG_TUD_AUDIO_TX_ITEMSIZE 4 #endif +#endif + +#if CFG_TUD_AUDIO_TX_ITEMSIZE < CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX +#error FIFO element size (ITEMSIZE) must not be smaller then sample size +#endif #endif @@ -170,9 +176,15 @@ extern "C" { bool tud_audio_n_mounted (uint8_t itf); #if CFG_TUD_AUDIO_EPSIZE_OUT && CFG_TUD_AUDIO_RX_FIFO_SIZE +#if CFG_TUD_AUDIO_RX_FIFO_COUNT > 1 uint16_t tud_audio_n_available (uint8_t itf, uint8_t channelId); uint16_t tud_audio_n_read (uint8_t itf, uint8_t channelId, void* buffer, uint16_t bufsize); void tud_audio_n_read_flush (uint8_t itf, uint8_t channelId); +#else +uint16_t tud_audio_n_available (uint8_t itf); +uint16_t tud_audio_n_read (uint8_t itf, void* buffer, uint16_t bufsize); +void tud_audio_n_read_flush (uint8_t itf); +#endif #endif /* This function is intended for later use once EP buffers (at least for ISO EPs) are implemented as ring buffers @@ -182,7 +194,12 @@ uint16_t tud_audio_n_write_ep_in_buffer(uint8_t itf, const void * data, uint16_t */ #if CFG_TUD_AUDIO_EPSIZE_IN && CFG_TUD_AUDIO_TX_FIFO_SIZE +#if CFG_TUD_AUDIO_TX_FIFO_COUNT > 1 uint16_t tud_audio_n_write (uint8_t itf, uint8_t channelId, const void * data, uint16_t len); +#else +uint16_t tud_audio_n_write (uint8_t itf, const void * data, uint16_t len); +#endif +uint16_t tud_audio_n_write_flush(uint8_t itf); #endif #if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN > 0 @@ -196,23 +213,27 @@ uint16_t tud_audio_int_ctr_n_write (uint8_t itf, uint8_t const* buffer, // Application API (Interface0) //--------------------------------------------------------------------+ -inline bool tud_audio_mounted (void); +static inline bool tud_audio_mounted (void); #if CFG_TUD_AUDIO_EPSIZE_OUT && CFG_TUD_AUDIO_RX_FIFO_SIZE -inline uint16_t tud_audio_available (void); -inline uint16_t tud_audio_read (void* buffer, uint16_t bufsize); -inline void tud_audio_read_flush (void); +static inline uint16_t tud_audio_available (void); +static inline uint16_t tud_audio_read (void* buffer, uint16_t bufsize); +static inline void tud_audio_read_flush (void); #endif #if CFG_TUD_AUDIO_EPSIZE_IN && CFG_TUD_AUDIO_TX_FIFO_SIZE -inline uint16_t tud_audio_write (uint8_t channelId, uint8_t const* buffer, uint16_t bufsize); +#if CFG_TUD_AUDIO_TX_FIFO_COUNT > 1 +static inline uint16_t tud_audio_write (uint8_t channelId, uint8_t const* buffer, uint16_t bufsize); +#else +static inline uint16_t tud_audio_write (uint8_t const* buffer, uint16_t bufsize); +#endif #endif #if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN > 0 -inline uint32_t tud_audio_int_ctr_available (void); -inline uint32_t tud_audio_int_ctr_read (void* buffer, uint32_t bufsize); -inline void tud_audio_int_ctr_read_flush (void); -inline uint32_t tud_audio_int_ctr_write (uint8_t const* buffer, uint32_t bufsize); +static inline uint32_t tud_audio_int_ctr_available (void); +static inline uint32_t tud_audio_int_ctr_read (void* buffer, uint32_t bufsize); +static inline void tud_audio_int_ctr_read_flush (void); +static inline uint32_t tud_audio_int_ctr_write (uint8_t const* buffer, uint32_t bufsize); #endif // Buffer control EP data and schedule a transmit @@ -238,6 +259,11 @@ TU_ATTR_WEAK bool tud_audio_rx_done_cb(uint8_t rhport, uint8_t * buffer, uint16_ #if CFG_TUD_AUDIO_EPSIZE_OUT > 0 && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP TU_ATTR_WEAK bool tud_audio_fb_done_cb(uint8_t rhport); +// User code should call this function with feedback value in 16.16 format for FS and HS. +// Value will be corrected for FS to 10.14 format automatically. +// (see Universal Serial Bus Specification Revision 2.0 5.12.4.2). +// Feedback value will be sent at FB endpoint interval till it's changed. +bool tud_audio_fb_set(uint8_t rhport, uint32_t feedback); #endif #if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN @@ -269,52 +295,85 @@ TU_ATTR_WEAK bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_reque // Inline Functions //--------------------------------------------------------------------+ -inline bool tud_audio_mounted(void) +static inline bool tud_audio_mounted(void) { return tud_audio_n_mounted(0); } -#if CFG_TUD_AUDIO_EPSIZE_IN && CFG_TUD_AUDIO_TX_FIFO_SIZE -inline uint16_t tud_audio_write (uint8_t channelId, uint8_t const* buffer, uint16_t bufsize) // Short version if only one audio function is used +#if CFG_TUD_AUDIO_EPSIZE_IN +#if CFG_TUD_AUDIO_TX_FIFO_SIZE && CFG_TUD_AUDIO_TX_FIFO_COUNT > 1 +static inline uint16_t tud_audio_write (uint8_t channelId, uint8_t const* buffer, uint16_t n_bytes) // Short version if only one audio function is used { - return tud_audio_n_write(0, channelId, buffer, bufsize); + return tud_audio_n_write(0, channelId, buffer, n_bytes); +} +#else +static inline uint16_t tud_audio_write (uint8_t const* buffer, uint16_t n_bytes) // Short version if only one audio function is used +{ + return tud_audio_n_write(0, buffer, n_bytes); +} +#endif + +static inline uint16_t tud_audio_write_flush (void) // Short version if only one audio function is used +{ +#if CFG_TUD_AUDIO_TX_FIFO_SIZE + return tud_audio_n_write_flush(0); +#else + return 0; +#endif } #endif // CFG_TUD_AUDIO_EPSIZE_IN && CFG_TUD_AUDIO_TX_FIFO_SIZE #if CFG_TUD_AUDIO_EPSIZE_OUT && CFG_TUD_AUDIO_RX_FIFO_SIZE -inline uint16_t tud_audio_available(uint8_t channelId) +#if CFG_TUD_AUDIO_RX_FIFO_COUNT > 1 +static inline uint16_t tud_audio_available(uint8_t channelId) { return tud_audio_n_available(0, channelId); } -inline uint16_t tud_audio_read(uint8_t channelId, void* buffer, uint16_t bufsize) +static inline uint16_t tud_audio_read(uint8_t channelId, void* buffer, uint16_t bufsize) { return tud_audio_n_read(0, channelId, buffer, bufsize); } -inline void tud_audio_read_flush(uint8_t channelId) +static inline void tud_audio_read_flush(uint8_t channelId) { tud_audio_n_read_flush(0, channelId); } +#else +static inline uint16_t tud_audio_available(void) +{ + return tud_audio_n_available(0); +} + +static inline uint16_t tud_audio_read(void *buffer, uint16_t bufsize) +{ + return tud_audio_n_read(0, buffer, bufsize); +} + +static inline void tud_audio_read_flush(void) +{ + tud_audio_n_read_flush(0); +} +#endif #endif #if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN > 0 -inline uint16_t tud_audio_int_ctr_available(void) +static inline uint16_t tud_audio_int_ctr_available(void) { return tud_audio_int_ctr_n_available(0); } -inline uint16_t tud_audio_int_ctr_read(void* buffer, uint16_t bufsize) +static inline uint16_t tud_audio_int_ctr_read(void* buffer, uint16_t bufsize) { return tud_audio_int_ctr_n_read(0, buffer, bufsize); } -inline void tud_audio_int_ctr_read_flush(void) +static inline void tud_audio_int_ctr_read_flush(void) { return tud_audio_int_ctr_n_read_flush(0); } -inline uint16_t tud_audio_int_ctr_write(uint8_t const* buffer, uint16_t bufsize) +static inline uint16_t tud_audio_int_ctr_write(uint8_t const* buffer, uint16_t bufsize) { return tud_audio_int_ctr_n_write(0, buffer, bufsize); } diff --git a/src/device/usbd.h b/src/device/usbd.h index 43af2507..7363159a 100644 --- a/src/device/usbd.h +++ b/src/device/usbd.h @@ -377,6 +377,11 @@ TU_ATTR_WEAK bool tud_vendor_control_complete_cb(uint8_t rhport, tusb_control_re #define TUD_AUDIO_DESC_CS_AS_ISO_EP(_attr, _ctrl, _lockdelayunit, _lockdelay) \ TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN, TUSB_DESC_CS_ENDPOINT, AUDIO_CS_EP_SUBTYPE_GENERAL, _attr, _ctrl, _lockdelayunit, U16_TO_U8S_LE(_lockdelay) +/* 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, (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_NO_SYNC | TUSB_ISO_EP_ATT_EXPLICIT_FB), U16_TO_U8S_LE(4), _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 @@ -426,6 +431,56 @@ TU_ATTR_WEAK bool tud_vendor_control_complete_cb(uint8_t rhport, tusb_control_re /* 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) +// AUDIO simple descriptor (UAC2) for mono speaker +// - 1 Input Terminal, 2 Feature Unit (Mute and Volume Control), 3 Output Terminal, 4 Clock Source + +#define TUD_AUDIO_SPEAKER_MONO_FB_DESC_LEN (TUD_AUDIO_DESC_IAD_LEN\ + + TUD_AUDIO_DESC_STD_AC_LEN\ + + TUD_AUDIO_DESC_CS_AC_LEN\ + + TUD_AUDIO_DESC_CLK_SRC_LEN\ + + TUD_AUDIO_DESC_INPUT_TERM_LEN\ + + TUD_AUDIO_DESC_OUTPUT_TERM_LEN\ + + TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN\ + + TUD_AUDIO_DESC_STD_AS_INT_LEN\ + + TUD_AUDIO_DESC_STD_AS_INT_LEN\ + + TUD_AUDIO_DESC_CS_AS_INT_LEN\ + + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN\ + + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN\ + + 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) \ + /* Standard Interface Association Descriptor (IAD) */\ + TUD_AUDIO_DESC_IAD(/*_firstitfs*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\ + /* Standard AC Interface Descriptor(4.7.1) */\ + TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\ + /* Class-Specific AC Interface Header Descriptor(4.7.2) */\ + TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO_FUNC_DESKTOP_SPEAKER, /*_totallen*/ TUD_AUDIO_DESC_CLK_SRC_LEN+TUD_AUDIO_DESC_INPUT_TERM_LEN+TUD_AUDIO_DESC_OUTPUT_TERM_LEN+TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN, /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS),\ + /* Clock Source Descriptor(4.7.2.1) */\ + TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ 0x04, /*_attr*/ AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK, /*_ctrl*/ (AUDIO_CTRL_R << AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ 0x01, /*_stridx*/ 0x00),\ + /* Input Terminal Descriptor(4.7.2.4) */\ + TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ 0x01, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_clkid*/ 0x04, /*_nchannelslogical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00),\ + /* 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),\ + /* 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),\ + /* Standard AS Interface Descriptor(4.9.1) */\ + /* Interface 1, Alternate 1 - alternate interface for data streaming */\ + TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x01, /*_nEPs*/ 0x02, /*_stridx*/ 0x00),\ + /* Class-Specific AS Interface Descriptor(4.9.2) */\ + TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ 0x01, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\ + /* 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*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ (CFG_TUSB_RHPORT0_MODE & OPT_MODE_HIGH_SPEED) ? 0x04 : 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_USBTMC/USB488 -------------// #define TUD_USBTMC_APP_CLASS (TUSB_CLASS_APPLICATION_SPECIFIC) #define TUD_USBTMC_APP_SUBCLASS 0x03u diff --git a/src/portable/st/synopsys/dcd_synopsys.c b/src/portable/st/synopsys/dcd_synopsys.c index c1b087da..4c670515 100644 --- a/src/portable/st/synopsys/dcd_synopsys.c +++ b/src/portable/st/synopsys/dcd_synopsys.c @@ -136,6 +136,7 @@ typedef struct { uint8_t * buffer; uint16_t total_len; uint16_t max_size; + uint8_t interval; } xfer_ctl_t; // EP size and transfer type report @@ -440,7 +441,7 @@ static void edpt_schedule_packets(uint8_t rhport, uint8_t const epnum, uint8_t c in_ep[epnum].DIEPCTL |= USB_OTG_DIEPCTL_EPENA | USB_OTG_DIEPCTL_CNAK; // For ISO endpoint set correct odd/even bit for next frame. - if ((in_ep[epnum].DIEPCTL & USB_OTG_DIEPCTL_EPTYP) == USB_OTG_DIEPCTL_EPTYP_0) + if ((in_ep[epnum].DIEPCTL & USB_OTG_DIEPCTL_EPTYP) == USB_OTG_DIEPCTL_EPTYP_0 && (XFER_CTL_BASE(epnum, dir))->interval == 1) { // Take odd/even bit from frame counter. uint32_t const odd_frame_now = (dev->DSTS & (1u << USB_OTG_DSTS_FNSOF_Pos)); @@ -457,6 +458,12 @@ static void edpt_schedule_packets(uint8_t rhport, uint8_t const epnum, uint8_t c ((total_bytes << USB_OTG_DOEPTSIZ_XFRSIZ_Pos) & USB_OTG_DOEPTSIZ_XFRSIZ_Msk); out_ep[epnum].DOEPCTL |= USB_OTG_DOEPCTL_EPENA | USB_OTG_DOEPCTL_CNAK; + if ((out_ep[epnum].DOEPCTL & USB_OTG_DOEPCTL_EPTYP) == USB_OTG_DOEPCTL_EPTYP_0 && (XFER_CTL_BASE(epnum, dir))->interval == 1) + { + // Take odd/even bit from frame counter. + uint32_t const odd_frame_now = (dev->DSTS & (1u << USB_OTG_DSTS_FNSOF_Pos)); + out_ep[epnum].DOEPCTL |= (odd_frame_now ? USB_OTG_DOEPCTL_SD0PID_SEVNFRM_Msk : USB_OTG_DOEPCTL_SODDFRM_Msk); + } } } @@ -608,6 +615,7 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt) xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir); xfer->max_size = desc_edpt->wMaxPacketSize.size; + xfer->interval = desc_edpt->bInterval; if(dir == TUSB_DIR_OUT) { @@ -809,20 +817,7 @@ static void dcd_edpt_disable (uint8_t rhport, uint8_t ep_addr, bool stall) */ void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr) { - USB_OTG_GlobalTypeDef * usb_otg = GLOBAL_BASE(rhport); - - uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); - dcd_edpt_disable(rhport, ep_addr, false); -// if (dir == TUSB_DIR_IN) -// { -// uint16_t const fifo_size = (usb_otg->DIEPTXF[epnum - 1] & USB_OTG_DIEPTXF_INEPTXFD_Msk) >> USB_OTG_DIEPTXF_INEPTXFD_Pos; -// uint16_t const fifo_start = (usb_otg->DIEPTXF[epnum - 1] & USB_OTG_DIEPTXF_INEPTXSA_Msk) >> USB_OTG_DIEPTXF_INEPTXSA_Pos; -// // For now only endpoint that has FIFO at the end of FIFO memory can be closed without fuss. -// TU_ASSERT(fifo_start + fifo_size == _allocated_fifo_words,); -// _allocated_fifo_words -= fifo_size; -// } } void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr) @@ -1241,34 +1236,43 @@ TU_ATTR_WEAK bool dcd_alloc_mem_for_conf(uint8_t rhport, tusb_desc_configuration // Determine number of used out EPs of current configuration and size of two biggest out EPs uint8_t nUsedOutEPs = 0, cnt_ep, cnt_tt; - bool tmp; uint16_t sz[2] = {0, 0}; + uint16_t fifo_depth; for (cnt_ep = 0; cnt_ep < EP_MAX; cnt_ep++) { - tmp = false; for (cnt_tt = 0; cnt_tt <= TUSB_XFER_INTERRUPT; cnt_tt++) { - tmp |= report.ep_transfer_type[cnt_ep][TUSB_DIR_OUT][cnt_tt]; + if (report.ep_transfer_type[cnt_ep][TUSB_DIR_OUT][cnt_tt]) + { + nUsedOutEPs++; + break; + } } - nUsedOutEPs += tmp; - if (sz[0] < report.ep_size[cnt_ep][TUSB_DIR_OUT]) + fifo_depth = report.ep_size[cnt_ep][TUSB_DIR_OUT] / 4 + 1; + if (sz[0] < fifo_depth) { sz[1] = sz[0]; - sz[0] = report.ep_size[cnt_ep][TUSB_DIR_OUT]; + sz[0] = fifo_depth; + } + else if (sz[1] < report.ep_size[cnt_ep][TUSB_DIR_OUT]) + { + sz[1] = fifo_depth; } } // For configuration use the approach as explained in bus_reset() - _allocated_fifo_words = 15 + 2*nUsedOutEPs + (sz[0] / 4) + (sz[0] % 4 > 0 ? 1 : 0) + (sz[1] / 4) + (sz[1] % 4 > 0 ? 1 : 0) + 2; // again, i do not really know why we need + 2 but otherwise it does not work + _allocated_fifo_words = 13 + 1 + 1 + 2 * nUsedOutEPs + sz[0] + sz[1] + 2; // again, i do not really know why we need + 2 but otherwise it does not work usb_otg->GRXFSIZ = _allocated_fifo_words; // Control IN uses FIFO 0 with report.ep_size[0][TUSB_DIR_IN] bytes ( report.ep_size[0][TUSB_DIR_IN]/4 32-bit word ) - usb_otg->DIEPTXF0_HNPTXFSIZ = (report.ep_size[0][TUSB_DIR_IN]/4 << USB_OTG_TX0FD_Pos) | _allocated_fifo_words; + fifo_depth = report.ep_size[0][TUSB_DIR_IN] / 4; + fifo_depth = tu_max16(16, fifo_depth); + usb_otg->DIEPTXF0_HNPTXFSIZ = (fifo_depth << USB_OTG_TX0FD_Pos) | _allocated_fifo_words; - _allocated_fifo_words += report.ep_size[0][TUSB_DIR_IN]/4; // Since EP0 size MUST be a power of two we do not need to take care of remainders + _allocated_fifo_words += fifo_depth; // For configuration of remaining in EPs use the approach as explained in dcd_edpt_open() except that: // - ISO EPs only get EP size as FIFO size. More makes no sense since within one frame precisely EP size bytes are transfered and not more. @@ -1307,11 +1311,14 @@ TU_ATTR_WEAK bool dcd_alloc_mem_for_conf(uint8_t rhport, tusb_desc_configuration // Required space by EPs in words, number of bulk and control EPs uint16_t ep_sz_total = 0; + // Number of bulk and control EPs uint8_t nbc = 0; // EP0 is already taken care of so exclude that here for (cnt_ep = 1; cnt_ep < EP_MAX; cnt_ep++) { - ep_sz_total += report.ep_size[cnt_ep][TUSB_DIR_IN] / 4 + (report.ep_size[cnt_ep][TUSB_DIR_IN] % 4 > 0 ? 1 : 0); // Since we need full words take care of remainders! + fifo_depth = (report.ep_size[cnt_ep][TUSB_DIR_IN] + 3) / 4; // Since we need full words take care of remainders! + if (fifo_depth > 0 && fifo_depth < 16) fifo_depth = 16; // Minimum FIFO depth is 16 + ep_sz_total += fifo_depth; nbc += (report.ep_transfer_type[cnt_ep][TUSB_DIR_IN][TUSB_XFER_BULK] | report.ep_transfer_type[cnt_ep][TUSB_DIR_IN][TUSB_XFER_CONTROL]); } @@ -1321,8 +1328,7 @@ TU_ATTR_WEAK bool dcd_alloc_mem_for_conf(uint8_t rhport, tusb_desc_configuration return false; } - uint16_t extra_space = nbc > 0 ? fifo_remaining / nbc : 0; // If no bulk or control EPs are used we just leave the rest of the memory unused - uint16_t fifo_size; + uint16_t extra_space = nbc > 0 ? (fifo_remaining - ep_sz_total) / nbc : 0; // If no bulk or control EPs are used we just leave the rest of the memory unused // Setup FIFOs for (cnt_ep = 1; cnt_ep < EP_MAX; cnt_ep++) @@ -1330,9 +1336,10 @@ TU_ATTR_WEAK bool dcd_alloc_mem_for_conf(uint8_t rhport, tusb_desc_configuration // If EP is used if (report.ep_size[cnt_ep][TUSB_DIR_IN] > 0) { - fifo_size = report.ep_size[cnt_ep][TUSB_DIR_IN] / 4 + (report.ep_size[cnt_ep][TUSB_DIR_IN] % 4 > 0 ? 1 : 0) + ((report.ep_transfer_type[cnt_ep][TUSB_DIR_IN][TUSB_XFER_BULK] || report.ep_transfer_type[cnt_ep][TUSB_DIR_IN][TUSB_XFER_CONTROL]) ? extra_space : 0); - usb_otg->DIEPTXF[cnt_ep - 1] = (fifo_size << USB_OTG_DIEPTXF_INEPTXFD_Pos) | _allocated_fifo_words; - _allocated_fifo_words += fifo_size; + fifo_depth = (report.ep_size[cnt_ep][TUSB_DIR_IN] + 3) / 4 + ((report.ep_transfer_type[cnt_ep][TUSB_DIR_IN][TUSB_XFER_BULK] || report.ep_transfer_type[cnt_ep][TUSB_DIR_IN][TUSB_XFER_CONTROL]) ? extra_space : 0); + fifo_depth = tu_max16(16, fifo_depth); + usb_otg->DIEPTXF[cnt_ep - 1] = (fifo_depth << USB_OTG_DIEPTXF_INEPTXFD_Pos) | _allocated_fifo_words; + _allocated_fifo_words += fifo_depth; } }