|
|
|
|
|
|
|
|
|
|
|
|
|
|
extern volatile uint8_t usb_high_speed; |
|
|
extern volatile uint8_t usb_high_speed; |
|
|
static void rx_event(transfer_t *t); |
|
|
static void rx_event(transfer_t *t); |
|
|
|
|
|
static void rx_queue_transfer(void); |
|
|
|
|
|
|
|
|
static transfer_t rx_transfer __attribute__ ((used, aligned(32))); |
|
|
|
|
|
|
|
|
/*static*/ transfer_t rx_transfer __attribute__ ((used, aligned(32))); |
|
|
|
|
|
/*static*/ transfer_t sync_transfer __attribute__ ((used, aligned(32))); |
|
|
DMAMEM static uint8_t rx_buffer[AUDIO_RX_SIZE] __attribute__ ((aligned(32))); |
|
|
DMAMEM static uint8_t rx_buffer[AUDIO_RX_SIZE] __attribute__ ((aligned(32))); |
|
|
|
|
|
|
|
|
//#define DMABUFATTR __attribute__ ((section(".dmabuffers"), aligned (4))) |
|
|
|
|
|
//uint16_t usb_audio_receive_buffer[AUDIO_RX_SIZE/2] DMABUFATTR; |
|
|
|
|
|
//uint32_t usb_audio_sync_feedback DMABUFATTR; |
|
|
|
|
|
|
|
|
DMAMEM uint32_t usb_audio_sync_feedback; |
|
|
|
|
|
|
|
|
uint8_t usb_audio_receive_setting=0; |
|
|
uint8_t usb_audio_receive_setting=0; |
|
|
uint8_t usb_audio_transmit_setting=0; |
|
|
uint8_t usb_audio_transmit_setting=0; |
|
|
|
|
|
uint8_t usb_audio_sync_nbytes; |
|
|
|
|
|
uint8_t usb_audio_sync_rshift; |
|
|
|
|
|
|
|
|
|
|
|
uint32_t feedback_accumulator; |
|
|
|
|
|
|
|
|
static uint32_t feedback_accumulator = 185042824; |
|
|
|
|
|
|
|
|
volatile uint32_t usb_audio_underrun_count; |
|
|
|
|
|
volatile uint32_t usb_audio_overrun_count; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void rx_queue_transfer(void) |
|
|
|
|
|
|
|
|
static void rx_event(transfer_t *t) |
|
|
{ |
|
|
{ |
|
|
|
|
|
if (t) { |
|
|
|
|
|
int len = AUDIO_RX_SIZE - ((rx_transfer.status >> 16) & 0x7FFF); |
|
|
|
|
|
//printf("rx %u\n", len); |
|
|
|
|
|
usb_audio_receive_callback(len); |
|
|
|
|
|
} |
|
|
usb_prepare_transfer(&rx_transfer, rx_buffer, AUDIO_RX_SIZE, 0); |
|
|
usb_prepare_transfer(&rx_transfer, rx_buffer, AUDIO_RX_SIZE, 0); |
|
|
arm_dcache_delete(&rx_transfer, AUDIO_RX_SIZE); |
|
|
|
|
|
|
|
|
arm_dcache_delete(&rx_buffer, AUDIO_RX_SIZE); |
|
|
usb_receive(AUDIO_RX_ENDPOINT, &rx_transfer); |
|
|
usb_receive(AUDIO_RX_ENDPOINT, &rx_transfer); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void sync_event(transfer_t *t) |
|
|
|
|
|
{ |
|
|
|
|
|
// USB 2.0 Specification, 5.12.4.2 Feedback, pages 73-75 |
|
|
|
|
|
//printf("sync %x\n", sync_transfer.status); // too slow, can't print this much |
|
|
|
|
|
usb_audio_sync_feedback = feedback_accumulator >> usb_audio_sync_rshift; |
|
|
|
|
|
usb_prepare_transfer(&sync_transfer, &usb_audio_sync_feedback, usb_audio_sync_nbytes, 0); |
|
|
|
|
|
arm_dcache_delete(&usb_audio_sync_feedback, usb_audio_sync_nbytes); |
|
|
|
|
|
usb_transmit(AUDIO_SYNC_ENDPOINT, &sync_transfer); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
void usb_audio_configure(void) |
|
|
void usb_audio_configure(void) |
|
|
{ |
|
|
{ |
|
|
printf("usb_audio_configure\n"); |
|
|
printf("usb_audio_configure\n"); |
|
|
|
|
|
usb_audio_underrun_count = 0; |
|
|
|
|
|
usb_audio_overrun_count = 0; |
|
|
|
|
|
feedback_accumulator = 739875226; // 44.1 * 2^24 |
|
|
|
|
|
if (usb_high_speed) { |
|
|
|
|
|
usb_audio_sync_nbytes = 4; |
|
|
|
|
|
usb_audio_sync_rshift = 8; |
|
|
|
|
|
} else { |
|
|
|
|
|
usb_audio_sync_nbytes = 3; |
|
|
|
|
|
usb_audio_sync_rshift = 10; |
|
|
|
|
|
} |
|
|
memset(&rx_transfer, 0, sizeof(rx_transfer)); |
|
|
memset(&rx_transfer, 0, sizeof(rx_transfer)); |
|
|
usb_config_rx_iso(AUDIO_RX_ENDPOINT, AUDIO_RX_SIZE, 1, rx_event); |
|
|
usb_config_rx_iso(AUDIO_RX_ENDPOINT, AUDIO_RX_SIZE, 1, rx_event); |
|
|
rx_queue_transfer(); |
|
|
|
|
|
|
|
|
//rx_queue_transfer(); |
|
|
|
|
|
rx_event(NULL); |
|
|
|
|
|
memset(&sync_transfer, 0, sizeof(sync_transfer)); |
|
|
|
|
|
usb_config_tx_iso(AUDIO_SYNC_ENDPOINT, usb_audio_sync_nbytes, 1, sync_event); |
|
|
|
|
|
sync_event(NULL); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void AudioInputUSB::begin(void) |
|
|
void AudioInputUSB::begin(void) |
|
|
|
|
|
|
|
|
// but also because the PC may stop transmitting data, which |
|
|
// but also because the PC may stop transmitting data, which |
|
|
// means we no longer get receive callbacks from usb.c |
|
|
// means we no longer get receive callbacks from usb.c |
|
|
update_responsibility = false; |
|
|
update_responsibility = false; |
|
|
//usb_audio_sync_feedback = feedback_accumulator >> 8; |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static void copy_to_buffers(const uint32_t *src, int16_t *left, int16_t *right, unsigned int len) |
|
|
static void copy_to_buffers(const uint32_t *src, int16_t *left, int16_t *right, unsigned int len) |
|
|
|
|
|
|
|
|
// Called from the USB interrupt when an isochronous packet arrives |
|
|
// Called from the USB interrupt when an isochronous packet arrives |
|
|
// we must completely remove it from the receive buffer before returning |
|
|
// we must completely remove it from the receive buffer before returning |
|
|
// |
|
|
// |
|
|
static void rx_event(transfer_t *t) |
|
|
|
|
|
{ |
|
|
|
|
|
unsigned int len = AUDIO_RX_SIZE - ((t->status >> 16) & 0x7FFF); |
|
|
|
|
|
//int len = AUDIO_RX_SIZE - ((rx_transfer.status >> 16) & 0x7FFF); |
|
|
|
|
|
printf("rx %u\n", len); |
|
|
|
|
|
// TODO: actually move the data from USB to audio lib |
|
|
|
|
|
usb_audio_receive_callback(len); |
|
|
|
|
|
rx_queue_transfer(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#if 1 |
|
|
#if 1 |
|
|
void usb_audio_receive_callback(unsigned int len) |
|
|
void usb_audio_receive_callback(unsigned int len) |
|
|
{ |
|
|
{ |
|
|
|
|
|
|
|
|
if (AudioInputUSB::ready_left || AudioInputUSB::ready_right) { |
|
|
if (AudioInputUSB::ready_left || AudioInputUSB::ready_right) { |
|
|
// buffer overrun, PC sending too fast |
|
|
// buffer overrun, PC sending too fast |
|
|
AudioInputUSB::incoming_count = count + avail; |
|
|
AudioInputUSB::incoming_count = count + avail; |
|
|
//if (len > 0) { |
|
|
|
|
|
//serial_print("!"); |
|
|
|
|
|
|
|
|
if (len > 0) { |
|
|
|
|
|
usb_audio_overrun_count++; |
|
|
|
|
|
printf("!"); |
|
|
//serial_phex(len); |
|
|
//serial_phex(len); |
|
|
//} |
|
|
|
|
|
|
|
|
} |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
send: |
|
|
send: |
|
|
|
|
|
|
|
|
__enable_irq(); |
|
|
__enable_irq(); |
|
|
if (f) { |
|
|
if (f) { |
|
|
int diff = AUDIO_BLOCK_SAMPLES/2 - (int)c; |
|
|
int diff = AUDIO_BLOCK_SAMPLES/2 - (int)c; |
|
|
feedback_accumulator += diff / 3; |
|
|
|
|
|
uint32_t feedback = (feedback_accumulator >> 8) + diff * 100; |
|
|
|
|
|
#ifdef MACOSX_ADAPTIVE_LIMIT |
|
|
|
|
|
if (feedback > 722698) feedback = 722698; |
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
feedback_accumulator += diff * 2; |
|
|
|
|
|
|
|
|
|
|
|
//__disable_irq(); |
|
|
|
|
|
//printf("fb:%x\n", feedback_accumulator); |
|
|
|
|
|
//__enable_irq(); |
|
|
|
|
|
//uint32_t feedback = (feedback_accumulator >> 8) + diff * 100; |
|
|
//usb_audio_sync_feedback = feedback; |
|
|
//usb_audio_sync_feedback = feedback; |
|
|
//if (diff > 0) { |
|
|
//if (diff > 0) { |
|
|
//serial_print("."); |
|
|
//serial_print("."); |
|
|
|
|
|
|
|
|
//serial_phex(c); |
|
|
//serial_phex(c); |
|
|
//serial_print("."); |
|
|
//serial_print("."); |
|
|
if (!left || !right) { |
|
|
if (!left || !right) { |
|
|
//serial_print("#"); // buffer underrun - PC sending too slow |
|
|
|
|
|
|
|
|
usb_audio_underrun_count++; |
|
|
|
|
|
printf("#"); // buffer underrun - PC sending too slow |
|
|
//if (f) feedback_accumulator += 10 << 8; |
|
|
//if (f) feedback_accumulator += 10 << 8; |
|
|
} |
|
|
} |
|
|
if (left) { |
|
|
if (left) { |