audio_4_channel_mic_freertos : merge changes from audio_4_channel_mic.
This commit is contained in:
		@@ -29,6 +29,11 @@ target_include_directories(${PROJECT} PUBLIC
 | 
			
		||||
  ${CMAKE_CURRENT_SOURCE_DIR}/src
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
# Add libm for GCC
 | 
			
		||||
if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
 | 
			
		||||
  target_link_libraries(${PROJECT} PUBLIC m)
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
# Configure compilation flags and libraries for the example with FreeRTOS.
 | 
			
		||||
# See the corresponding function in hw/bsp/FAMILY/family.cmake for details.
 | 
			
		||||
family_configure_device_example(${PROJECT} freertos)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,4 @@
 | 
			
		||||
CONFIG_IDF_CMAKE=y
 | 
			
		||||
CONFIG_FREERTOS_HZ=1000
 | 
			
		||||
CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK=y
 | 
			
		||||
CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y
 | 
			
		||||
 
 | 
			
		||||
@@ -34,6 +34,7 @@
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <math.h>
 | 
			
		||||
 | 
			
		||||
#include "bsp/board_api.h"
 | 
			
		||||
#include "tusb.h"
 | 
			
		||||
@@ -60,13 +61,13 @@
 | 
			
		||||
  #define USBD_STACK_SIZE    (4*configMINIMAL_STACK_SIZE/2) * (CFG_TUSB_DEBUG ? 2 : 1)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define BLINKY_STACK_SIZE   configMINIMAL_STACK_SIZE
 | 
			
		||||
#define AUDIO_STACK_SIZE    configMINIMAL_STACK_SIZE
 | 
			
		||||
 | 
			
		||||
//--------------------------------------------------------------------+
 | 
			
		||||
// MACRO CONSTANT TYPEDEF PROTYPES
 | 
			
		||||
//--------------------------------------------------------------------+
 | 
			
		||||
 | 
			
		||||
#ifndef AUDIO_SAMPLE_RATE
 | 
			
		||||
#define AUDIO_SAMPLE_RATE   48000
 | 
			
		||||
#endif
 | 
			
		||||
#define AUDIO_SAMPLE_RATE   CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE
 | 
			
		||||
 | 
			
		||||
/* Blink pattern
 | 
			
		||||
 * - 250 ms  : device not mounted
 | 
			
		||||
@@ -79,12 +80,19 @@ enum  {
 | 
			
		||||
  BLINK_SUSPENDED = 2500,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// static timer
 | 
			
		||||
StaticTimer_t blinky_tmdef;
 | 
			
		||||
TimerHandle_t blinky_tm;
 | 
			
		||||
// static task
 | 
			
		||||
#if configSUPPORT_STATIC_ALLOCATION
 | 
			
		||||
StackType_t  blinky_stack[BLINKY_STACK_SIZE];
 | 
			
		||||
StaticTask_t blinky_taskdef;
 | 
			
		||||
 | 
			
		||||
StackType_t  usb_device_stack[USBD_STACK_SIZE];
 | 
			
		||||
StaticTask_t usb_device_taskdef;
 | 
			
		||||
 | 
			
		||||
StackType_t  audio_stack[AUDIO_STACK_SIZE];
 | 
			
		||||
StaticTask_t audio_taskdef;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED;
 | 
			
		||||
 | 
			
		||||
// Audio controls
 | 
			
		||||
// Current states
 | 
			
		||||
@@ -97,23 +105,23 @@ uint8_t clkValid;
 | 
			
		||||
audio_control_range_2_n_t(1) volumeRng[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX+1]; 			// Volume range state
 | 
			
		||||
audio_control_range_4_n_t(1) sampleFreqRng; 						// Sample frequency range state
 | 
			
		||||
 | 
			
		||||
// Audio test data
 | 
			
		||||
uint16_t i2s_dummy_buffer[CFG_TUD_AUDIO_EP_SZ_IN/2];   // Ensure half word aligned
 | 
			
		||||
uint16_t samples[] = {0, 0, 0, 0};
 | 
			
		||||
#if CFG_TUD_AUDIO_ENABLE_ENCODING
 | 
			
		||||
// Audio test data, each buffer contains 2 channels, buffer[0] for CH0-1, buffer[1] for CH1-2
 | 
			
		||||
uint16_t i2s_dummy_buffer[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX*CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE/1000/CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO];
 | 
			
		||||
#else
 | 
			
		||||
// Audio test data, 4 channels muxed together, buffer[0] for CH0, buffer[1] for CH1, buffer[2] for CH2, buffer[3] for CH3
 | 
			
		||||
uint16_t i2s_dummy_buffer[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX*CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE/1000];
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
void led_blinky_cb(TimerHandle_t xTimer);
 | 
			
		||||
void led_blinking_task(void* param);
 | 
			
		||||
void usb_device_task(void* param);
 | 
			
		||||
void audio_task(void);
 | 
			
		||||
void audio_task(void* param);
 | 
			
		||||
 | 
			
		||||
/*------------- MAIN -------------*/
 | 
			
		||||
int main(void)
 | 
			
		||||
{
 | 
			
		||||
  board_init();
 | 
			
		||||
 | 
			
		||||
  // soft timer for blinky
 | 
			
		||||
  blinky_tm = xTimerCreateStatic(NULL, pdMS_TO_TICKS(BLINK_NOT_MOUNTED), true, NULL, led_blinky_cb, &blinky_tmdef);
 | 
			
		||||
  xTimerStart(blinky_tm, 0);
 | 
			
		||||
 | 
			
		||||
  // Init values
 | 
			
		||||
  sampFreq = AUDIO_SAMPLE_RATE;
 | 
			
		||||
  clkValid = 1;
 | 
			
		||||
@@ -123,11 +131,58 @@ int main(void)
 | 
			
		||||
  sampleFreqRng.subrange[0].bMax = AUDIO_SAMPLE_RATE;
 | 
			
		||||
  sampleFreqRng.subrange[0].bRes = 0;
 | 
			
		||||
 | 
			
		||||
  // Generate dummy data
 | 
			
		||||
#if CFG_TUD_AUDIO_ENABLE_ENCODING
 | 
			
		||||
  uint16_t * p_buff = i2s_dummy_buffer[0];
 | 
			
		||||
  uint16_t dataVal = 0;
 | 
			
		||||
  for (uint16_t cnt = 0; cnt < AUDIO_SAMPLE_RATE/1000; cnt++)
 | 
			
		||||
  {
 | 
			
		||||
    // CH0 saw wave
 | 
			
		||||
    *p_buff++ = dataVal;
 | 
			
		||||
    // CH1 inverted saw wave
 | 
			
		||||
    *p_buff++ = 3200 + AUDIO_SAMPLE_RATE/1000 - dataVal;
 | 
			
		||||
    dataVal+= 32;
 | 
			
		||||
  }
 | 
			
		||||
  p_buff = i2s_dummy_buffer[1];
 | 
			
		||||
  for (uint16_t cnt = 0; cnt < AUDIO_SAMPLE_RATE/1000; cnt++)
 | 
			
		||||
  {
 | 
			
		||||
    // CH3 square wave
 | 
			
		||||
    *p_buff++ = cnt < (AUDIO_SAMPLE_RATE/1000/2) ? 3400:5000;
 | 
			
		||||
    // CH4 sinus wave
 | 
			
		||||
    float t = 2*3.1415f * cnt / (AUDIO_SAMPLE_RATE/1000);
 | 
			
		||||
    *p_buff++ = (uint16_t)((int16_t)(sinf(t) * 750) + 6000);
 | 
			
		||||
  }
 | 
			
		||||
#else
 | 
			
		||||
  uint16_t * p_buff = i2s_dummy_buffer;
 | 
			
		||||
  uint16_t dataVal = 0;
 | 
			
		||||
  for (uint16_t cnt = 0; cnt < AUDIO_SAMPLE_RATE/1000; cnt++)
 | 
			
		||||
  {
 | 
			
		||||
    // CH0 saw wave
 | 
			
		||||
    *p_buff++ = dataVal;
 | 
			
		||||
    // CH1 inverted saw wave
 | 
			
		||||
    *p_buff++ = 3200 + AUDIO_SAMPLE_RATE/1000 - dataVal;
 | 
			
		||||
    dataVal+= 32;
 | 
			
		||||
    // CH3 square wave
 | 
			
		||||
    *p_buff++ = cnt < (AUDIO_SAMPLE_RATE/1000/2) ? 3400:5000;
 | 
			
		||||
    // CH4 sinus wave
 | 
			
		||||
    float t = 2*3.1415f * cnt / (AUDIO_SAMPLE_RATE/1000);
 | 
			
		||||
    *p_buff++ = (uint16_t)((int16_t)(sinf(t) * 750) + 6000);
 | 
			
		||||
  }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if configSUPPORT_STATIC_ALLOCATION
 | 
			
		||||
  // blinky task
 | 
			
		||||
  xTaskCreateStatic(led_blinking_task, "blinky", BLINKY_STACK_SIZE, NULL, 1, blinky_stack, &blinky_taskdef);
 | 
			
		||||
 | 
			
		||||
  // Create a task for tinyusb device stack
 | 
			
		||||
  xTaskCreateStatic(usb_device_task, "usbd", USBD_STACK_SIZE, NULL, configMAX_PRIORITIES-1, usb_device_stack, &usb_device_taskdef);
 | 
			
		||||
 | 
			
		||||
   // Create a task for audio
 | 
			
		||||
  xTaskCreateStatic(audio_task, "audio", AUDIO_STACK_SIZE, NULL, configMAX_PRIORITIES-1, audio_stack, &audio_taskdef);
 | 
			
		||||
#else
 | 
			
		||||
  xTaskCreate(led_blinking_task, "blinky", BLINKY_STACK_SIZE, NULL, 1, NULL);
 | 
			
		||||
  xTaskCreate(usb_device_task, "usbd", USBD_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, NULL);
 | 
			
		||||
  xTaskCreate(audio_task, "audio", AUDIO_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, NULL);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  // skip starting scheduler (and return) for ESP32-S2 or ESP32-S3
 | 
			
		||||
@@ -175,13 +230,13 @@ void usb_device_task(void* param)
 | 
			
		||||
// Invoked when device is mounted
 | 
			
		||||
void tud_mount_cb(void)
 | 
			
		||||
{
 | 
			
		||||
  xTimerChangePeriod(blinky_tm, pdMS_TO_TICKS(BLINK_MOUNTED), 0);
 | 
			
		||||
  blink_interval_ms = BLINK_MOUNTED;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Invoked when device is unmounted
 | 
			
		||||
void tud_umount_cb(void)
 | 
			
		||||
{
 | 
			
		||||
  xTimerChangePeriod(blinky_tm, pdMS_TO_TICKS(BLINK_NOT_MOUNTED), 0);
 | 
			
		||||
  blink_interval_ms = BLINK_NOT_MOUNTED;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Invoked when usb bus is suspended
 | 
			
		||||
@@ -190,23 +245,36 @@ void tud_umount_cb(void)
 | 
			
		||||
void tud_suspend_cb(bool remote_wakeup_en)
 | 
			
		||||
{
 | 
			
		||||
  (void) remote_wakeup_en;
 | 
			
		||||
  xTimerChangePeriod(blinky_tm, pdMS_TO_TICKS(BLINK_SUSPENDED), 0);
 | 
			
		||||
  blink_interval_ms = BLINK_SUSPENDED;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Invoked when usb bus is resumed
 | 
			
		||||
void tud_resume_cb(void)
 | 
			
		||||
{
 | 
			
		||||
  xTimerChangePeriod(blinky_tm, pdMS_TO_TICKS(BLINK_MOUNTED), 0);
 | 
			
		||||
  blink_interval_ms = tud_mounted() ? BLINK_MOUNTED : BLINK_NOT_MOUNTED;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//--------------------------------------------------------------------+
 | 
			
		||||
// AUDIO Task
 | 
			
		||||
//--------------------------------------------------------------------+
 | 
			
		||||
 | 
			
		||||
void audio_task(void)
 | 
			
		||||
void audio_task(void* param)
 | 
			
		||||
{
 | 
			
		||||
  // Yet to be filled - e.g. put meas data into TX FIFOs etc.
 | 
			
		||||
  // asm("nop");
 | 
			
		||||
  (void) param;
 | 
			
		||||
  // Yet to be filled - e.g. read audio from I2S buffer.
 | 
			
		||||
  // Here we simulate a I2S receive callback every 1ms.
 | 
			
		||||
  while (1) {
 | 
			
		||||
    vTaskDelay(1);
 | 
			
		||||
#if CFG_TUD_AUDIO_ENABLE_ENCODING
 | 
			
		||||
  // Write I2S buffer into FIFO
 | 
			
		||||
    for (uint8_t cnt=0; cnt < 2; cnt++)
 | 
			
		||||
    {
 | 
			
		||||
      tud_audio_write_support_ff(cnt, i2s_dummy_buffer[cnt], AUDIO_SAMPLE_RATE/1000 * CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX * CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_TX);
 | 
			
		||||
    }
 | 
			
		||||
#else
 | 
			
		||||
    tud_audio_write(i2s_dummy_buffer, AUDIO_SAMPLE_RATE/1000 * CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX * CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX);
 | 
			
		||||
#endif
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//--------------------------------------------------------------------+
 | 
			
		||||
@@ -427,7 +495,8 @@ bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *
 | 
			
		||||
        {
 | 
			
		||||
          case AUDIO_CS_REQ_CUR:
 | 
			
		||||
            TU_LOG2("    Get Sample Freq.\r\n");
 | 
			
		||||
            return tud_control_xfer(rhport, p_request, &sampFreq, sizeof(sampFreq));
 | 
			
		||||
            // Buffered control transfer is needed for IN flow control to work
 | 
			
		||||
            return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &sampFreq, sizeof(sampFreq));
 | 
			
		||||
 | 
			
		||||
          case AUDIO_CS_REQ_RANGE:
 | 
			
		||||
            TU_LOG2("    Get Sample Freq. range\r\n");
 | 
			
		||||
@@ -463,7 +532,14 @@ bool tud_audio_tx_done_pre_load_cb(uint8_t rhport, uint8_t itf, uint8_t ep_in, u
 | 
			
		||||
  (void) ep_in;
 | 
			
		||||
  (void) cur_alt_setting;
 | 
			
		||||
 | 
			
		||||
  tud_audio_write((uint8_t*)i2s_dummy_buffer, CFG_TUD_AUDIO_EP_SZ_IN);
 | 
			
		||||
 | 
			
		||||
  // In read world application data flow is driven by I2S clock,
 | 
			
		||||
  // both tud_audio_tx_done_pre_load_cb() & tud_audio_tx_done_post_load_cb() are hardly used.
 | 
			
		||||
  // For example in your I2S receive callback:
 | 
			
		||||
  // void I2S_Rx_Callback(int channel, const void* data, uint16_t samples)
 | 
			
		||||
  // {
 | 
			
		||||
  //    tud_audio_write_support_ff(channel, data, samples * N_BYTES_PER_SAMPLE * N_CHANNEL_PER_FIFO);
 | 
			
		||||
  // }
 | 
			
		||||
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
@@ -476,14 +552,6 @@ bool tud_audio_tx_done_post_load_cb(uint8_t rhport, uint16_t n_bytes_copied, uin
 | 
			
		||||
  (void) ep_in;
 | 
			
		||||
  (void) cur_alt_setting;
 | 
			
		||||
 | 
			
		||||
  uint16_t* p_buff = i2s_dummy_buffer;
 | 
			
		||||
  for (int samples_num = 0; samples_num < AUDIO_SAMPLE_RATE/1000; samples_num++) {
 | 
			
		||||
    for (int ch=0; ch < CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX; ch++) {
 | 
			
		||||
      *p_buff++ = samples[ch];
 | 
			
		||||
      samples[ch] = samples[ch]+(ch+1);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -498,11 +566,17 @@ bool tud_audio_set_itf_close_EP_cb(uint8_t rhport, tusb_control_request_t const
 | 
			
		||||
///--------------------------------------------------------------------+
 | 
			
		||||
// BLINKING TASK
 | 
			
		||||
//--------------------------------------------------------------------+
 | 
			
		||||
void led_blinky_cb(TimerHandle_t xTimer)
 | 
			
		||||
{
 | 
			
		||||
  (void) xTimer;
 | 
			
		||||
void led_blinking_task(void* param) {
 | 
			
		||||
  (void) param;
 | 
			
		||||
  static uint32_t start_ms = 0;
 | 
			
		||||
  static bool led_state = false;
 | 
			
		||||
 | 
			
		||||
  board_led_write(led_state);
 | 
			
		||||
  led_state = 1 - led_state; // toggle
 | 
			
		||||
  while (1) {
 | 
			
		||||
    // Blink every interval ms
 | 
			
		||||
    vTaskDelay(blink_interval_ms / portTICK_PERIOD_MS);
 | 
			
		||||
    start_ms += blink_interval_ms;
 | 
			
		||||
 | 
			
		||||
    board_led_write(led_state);
 | 
			
		||||
    led_state = 1 - led_state; // toggle
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -109,24 +109,37 @@ extern "C" {
 | 
			
		||||
//--------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
// Have a look into audio_device.h for all configurations
 | 
			
		||||
#define CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE              48000
 | 
			
		||||
 | 
			
		||||
#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN                                 TUD_AUDIO_MIC_FOUR_CH_DESC_LEN
 | 
			
		||||
#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN                 TUD_AUDIO_MIC_FOUR_CH_DESC_LEN
 | 
			
		||||
 | 
			
		||||
#define CFG_TUD_AUDIO_FUNC_1_N_AS_INT                                 1
 | 
			
		||||
#define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ                              64
 | 
			
		||||
#define CFG_TUD_AUDIO_FUNC_1_N_AS_INT                 1
 | 
			
		||||
#define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ              64
 | 
			
		||||
 | 
			
		||||
#define CFG_TUD_AUDIO_ENABLE_EP_IN                                    1
 | 
			
		||||
#define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX                    2         // This value is not required by the driver, it parses this information from the descriptor once the alternate interface is set by the host - we use it for the setup
 | 
			
		||||
#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX                            4         // This value is not required by the driver, it parses this information from the descriptor once the alternate interface is set by the host - we use it for the setup
 | 
			
		||||
#define CFG_TUD_AUDIO_EP_SZ_IN                                        48 * CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX * CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX      // 48 Samples (48 kHz) x 2 Bytes/Sample x CFG_TUD_AUDIO_N_CHANNELS_TX Channels - the Windows driver always needs an extra sample per channel of space more, otherwise it complains... found by trial and error
 | 
			
		||||
#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX                             CFG_TUD_AUDIO_EP_SZ_IN
 | 
			
		||||
#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ                          CFG_TUD_AUDIO_EP_SZ_IN
 | 
			
		||||
#define CFG_TUD_AUDIO_ENABLE_EP_IN                    1
 | 
			
		||||
#define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX    2         // This value is not required by the driver, it parses this information from the descriptor once the alternate interface is set by the host - we use it for the setup
 | 
			
		||||
#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX            4         // This value is not required by the driver, it parses this information from the descriptor once the alternate interface is set by the host - we use it for the setup
 | 
			
		||||
#define CFG_TUD_AUDIO_EP_SZ_IN                        TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX)
 | 
			
		||||
 | 
			
		||||
#define CFG_TUD_AUDIO_ENABLE_ENCODING                                 0
 | 
			
		||||
#define CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING                          0
 | 
			
		||||
#define CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_TX                      2         // One I2S stream contains two channels, each stream is saved within one support FIFO - this value is currently fixed, the driver does not support a changing value
 | 
			
		||||
#define CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO                        (CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX / CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_TX)
 | 
			
		||||
#define CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ                       (CFG_TUD_AUDIO_EP_SZ_IN / CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO)
 | 
			
		||||
#define CFG_TUD_AUDIO_ENABLE_ENCODING                 1
 | 
			
		||||
#define CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL              1
 | 
			
		||||
 | 
			
		||||
#if CFG_TUD_AUDIO_ENABLE_ENCODING
 | 
			
		||||
 | 
			
		||||
#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX             CFG_TUD_AUDIO_EP_SZ_IN
 | 
			
		||||
#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ          CFG_TUD_AUDIO_EP_SZ_IN
 | 
			
		||||
 | 
			
		||||
#define CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING          1
 | 
			
		||||
#define CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_TX      2         // One I2S stream contains two channels, each stream is saved within one support FIFO - this value is currently fixed, the driver does not support a changing value
 | 
			
		||||
#define CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO        (CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX / CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_TX)
 | 
			
		||||
#define CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ       (TUD_OPT_HIGH_SPEED ? 32 : 4) * (CFG_TUD_AUDIO_EP_SZ_IN / CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO) // Example write FIFO every 1ms, so it should be 8 times larger for HS device
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX             CFG_TUD_AUDIO_EP_SZ_IN
 | 
			
		||||
#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ          (TUD_OPT_HIGH_SPEED ? 32 : 4) * CFG_TUD_AUDIO_EP_SZ_IN // Example write FIFO every 1ms, so it should be 8 times larger for HS device
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -23,6 +23,7 @@
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "bsp/board_api.h"
 | 
			
		||||
#include "tusb.h"
 | 
			
		||||
 | 
			
		||||
/* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug.
 | 
			
		||||
@@ -44,7 +45,7 @@ tusb_desc_device_t const desc_device =
 | 
			
		||||
    .bDescriptorType    = TUSB_DESC_DEVICE,
 | 
			
		||||
    .bcdUSB             = 0x0200,
 | 
			
		||||
 | 
			
		||||
    // Use Interface Association Descriptor (IAD) for CDC
 | 
			
		||||
    // Use Interface Association Descriptor (IAD) for Audio
 | 
			
		||||
    // As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1)
 | 
			
		||||
    .bDeviceClass       = TUSB_CLASS_MISC,
 | 
			
		||||
    .bDeviceSubClass    = MISC_SUBCLASS_COMMON,
 | 
			
		||||
@@ -96,7 +97,7 @@ enum
 | 
			
		||||
 | 
			
		||||
uint8_t const desc_configuration[] =
 | 
			
		||||
{
 | 
			
		||||
  // Interface count, string index, total length, attribute, power in mA
 | 
			
		||||
  // Config number, interface count, string index, total length, attribute, power in mA
 | 
			
		||||
  TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
 | 
			
		||||
 | 
			
		||||
  // Interface number, string index, EP Out & EP In address, EP size
 | 
			
		||||
@@ -116,50 +117,63 @@ uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
 | 
			
		||||
// String Descriptors
 | 
			
		||||
//--------------------------------------------------------------------+
 | 
			
		||||
 | 
			
		||||
// array of pointer to string descriptors
 | 
			
		||||
char const* string_desc_arr [] =
 | 
			
		||||
{
 | 
			
		||||
    (const char[]) { 0x09, 0x04 }, 	// 0: is supported language is English (0x0409)
 | 
			
		||||
    "PaniRCorp",                   	// 1: Manufacturer
 | 
			
		||||
    "MicNode_4_Ch",    		          // 2: Product
 | 
			
		||||
    "123458",                      	// 3: Serials, should use chip ID
 | 
			
		||||
    "UAC2",                     	 	// 4: Audio Interface
 | 
			
		||||
// String Descriptor Index
 | 
			
		||||
enum {
 | 
			
		||||
  STRID_LANGID = 0,
 | 
			
		||||
  STRID_MANUFACTURER,
 | 
			
		||||
  STRID_PRODUCT,
 | 
			
		||||
  STRID_SERIAL,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static uint16_t _desc_str[32];
 | 
			
		||||
// array of pointer to string descriptors
 | 
			
		||||
char const* string_desc_arr [] = {
 | 
			
		||||
    (const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
 | 
			
		||||
    "PaniRCorp",                   // 1: Manufacturer
 | 
			
		||||
    "MicNode_4_Ch",                // 2: Product
 | 
			
		||||
    NULL,                          // 3: Serials will use unique ID if possible
 | 
			
		||||
    "UAC2",                        // 4: Audio Interface
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static uint16_t _desc_str[32 + 1];
 | 
			
		||||
 | 
			
		||||
// Invoked when received GET STRING DESCRIPTOR request
 | 
			
		||||
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
 | 
			
		||||
uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid)
 | 
			
		||||
{
 | 
			
		||||
uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
 | 
			
		||||
  (void) langid;
 | 
			
		||||
  size_t chr_count;
 | 
			
		||||
 | 
			
		||||
  uint8_t chr_count;
 | 
			
		||||
  switch ( index ) {
 | 
			
		||||
    case STRID_LANGID:
 | 
			
		||||
      memcpy(&_desc_str[1], string_desc_arr[0], 2);
 | 
			
		||||
      chr_count = 1;
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
  if ( index == 0)
 | 
			
		||||
  {
 | 
			
		||||
    memcpy(&_desc_str[1], string_desc_arr[0], 2);
 | 
			
		||||
    chr_count = 1;
 | 
			
		||||
  }else
 | 
			
		||||
  {
 | 
			
		||||
    // Convert ASCII string into UTF-16
 | 
			
		||||
    case STRID_SERIAL:
 | 
			
		||||
      chr_count = board_usb_get_serial(_desc_str + 1, 32);
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    if ( !(index < sizeof(string_desc_arr)/sizeof(string_desc_arr[0])) ) return NULL;
 | 
			
		||||
    default:
 | 
			
		||||
      // Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors.
 | 
			
		||||
      // https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors
 | 
			
		||||
 | 
			
		||||
    const char* str = string_desc_arr[index];
 | 
			
		||||
      if ( !(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) ) return NULL;
 | 
			
		||||
 | 
			
		||||
    // Cap at max char
 | 
			
		||||
    chr_count = strlen(str);
 | 
			
		||||
    if ( chr_count > 31 ) chr_count = 31;
 | 
			
		||||
      const char *str = string_desc_arr[index];
 | 
			
		||||
 | 
			
		||||
    for(uint8_t i=0; i<chr_count; i++)
 | 
			
		||||
    {
 | 
			
		||||
      _desc_str[1+i] = str[i];
 | 
			
		||||
    }
 | 
			
		||||
      // Cap at max char
 | 
			
		||||
      chr_count = strlen(str);
 | 
			
		||||
      size_t const max_count = sizeof(_desc_str) / sizeof(_desc_str[0]) - 1; // -1 for string type
 | 
			
		||||
      if ( chr_count > max_count ) chr_count = max_count;
 | 
			
		||||
 | 
			
		||||
      // Convert ASCII string into UTF-16
 | 
			
		||||
      for ( size_t i = 0; i < chr_count; i++ ) {
 | 
			
		||||
        _desc_str[1 + i] = str[i];
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // first byte is length (including header), second byte is string type
 | 
			
		||||
  _desc_str[0] = (TUSB_DESC_STRING << 8 ) | (2*chr_count + 2);
 | 
			
		||||
  _desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8) | (2 * chr_count + 2));
 | 
			
		||||
 | 
			
		||||
  return _desc_str;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user