| if (cb) endpointN_notify_mask |= (1 << (ep + 16)); | if (cb) endpointN_notify_mask |= (1 << (ep + 16)); | ||||
| } | } | ||||
| void usb_config_rx_iso(uint32_t ep, uint32_t packet_size, int mult, void (*cb)(transfer_t *)) | |||||
| { | |||||
| if (mult < 1 || mult > 3) return; | |||||
| uint32_t config = (packet_size << 16) | (mult << 30); | |||||
| if (ep < 2 || ep > NUM_ENDPOINTS) return; | |||||
| usb_endpoint_config(endpoint_queue_head + ep * 2, config, cb); | |||||
| if (cb) endpointN_notify_mask |= (1 << ep); | |||||
| } | |||||
| void usb_config_tx_iso(uint32_t ep, uint32_t packet_size, int mult, void (*cb)(transfer_t *)) | |||||
| { | |||||
| if (mult < 1 || mult > 3) return; | |||||
| uint32_t config = (packet_size << 16) | (mult << 30); | |||||
| if (ep < 2 || ep > NUM_ENDPOINTS) return; | |||||
| usb_endpoint_config(endpoint_queue_head + ep * 2 + 1, config, cb); | |||||
| if (cb) endpointN_notify_mask |= (1 << (ep + 16)); | |||||
| } | |||||
| void usb_prepare_transfer(transfer_t *transfer, const void *data, uint32_t len, uint32_t param) | void usb_prepare_transfer(transfer_t *transfer, const void *data, uint32_t len, uint32_t param) |
| #include <Arduino.h> | #include <Arduino.h> | ||||
| #include "usb_dev.h" | #include "usb_dev.h" | ||||
| #include "usb_audio.h" | |||||
| #include "debug/printf.h" | #include "debug/printf.h" | ||||
| #ifdef AUDIO_INTERFACE | #ifdef AUDIO_INTERFACE | ||||
| // Uncomment this to work around a limitation in Macintosh adaptive rates | |||||
| // This is not a perfect solution. Details here: | |||||
| // https://forum.pjrc.com/threads/34855-Distorted-audio-when-using-USB-input-on-Teensy-3-1 | |||||
| //#define MACOSX_ADAPTIVE_LIMIT | |||||
| bool AudioInputUSB::update_responsibility; | bool AudioInputUSB::update_responsibility; | ||||
| audio_block_t * AudioInputUSB::incoming_left; | audio_block_t * AudioInputUSB::incoming_left; | ||||
| audio_block_t * AudioInputUSB::incoming_right; | audio_block_t * AudioInputUSB::incoming_right; | ||||
| static void rx_event(transfer_t *t); | static void rx_event(transfer_t *t); | ||||
| static transfer_t rx_transfer __attribute__ ((used, aligned(32))); | static transfer_t rx_transfer __attribute__ ((used, aligned(32))); | ||||
| /*DMAMEM*/ static uint8_t rx_buffer[AUDIO_RX_SIZE_12] __attribute__ ((aligned(32))); | |||||
| static uint16_t rx_max_size; | |||||
| DMAMEM static uint8_t rx_buffer[AUDIO_RX_SIZE] __attribute__ ((aligned(32))); | |||||
| //#define DMABUFATTR __attribute__ ((section(".dmabuffers"), aligned (4))) | //#define DMABUFATTR __attribute__ ((section(".dmabuffers"), aligned (4))) | ||||
| //uint16_t usb_audio_receive_buffer[AUDIO_RX_SIZE/2] DMABUFATTR; | //uint16_t usb_audio_receive_buffer[AUDIO_RX_SIZE/2] DMABUFATTR; | ||||
| static void rx_queue_transfer(void) | static void rx_queue_transfer(void) | ||||
| { | { | ||||
| usb_prepare_transfer(&rx_transfer, rx_buffer, rx_max_size, 0); | |||||
| arm_dcache_delete(&rx_transfer, rx_max_size); | |||||
| usb_prepare_transfer(&rx_transfer, rx_buffer, AUDIO_RX_SIZE, 0); | |||||
| arm_dcache_delete(&rx_transfer, AUDIO_RX_SIZE); | |||||
| usb_receive(AUDIO_RX_ENDPOINT, &rx_transfer); | usb_receive(AUDIO_RX_ENDPOINT, &rx_transfer); | ||||
| } | } | ||||
| void usb_audio_configure(void) | void usb_audio_configure(void) | ||||
| { | { | ||||
| printf("usb_audio_configure\n"); | printf("usb_audio_configure\n"); | ||||
| memset(&rx_transfer, 0, sizeof(rx_transfer)); | memset(&rx_transfer, 0, sizeof(rx_transfer)); | ||||
| rx_max_size = usb_high_speed ? AUDIO_RX_SIZE_480 : AUDIO_RX_SIZE_12; | |||||
| usb_config_rx(AUDIO_RX_ENDPOINT, rx_max_size, 0, rx_event); | |||||
| usb_config_rx_iso(AUDIO_RX_ENDPOINT, AUDIO_RX_SIZE, 1, rx_event); | |||||
| rx_queue_transfer(); | rx_queue_transfer(); | ||||
| } | } | ||||
| void AudioInputUSB::begin(void) | void AudioInputUSB::begin(void) | ||||
| { | { | ||||
| incoming_count = 0; | incoming_count = 0; | ||||
| } | } | ||||
| } | } | ||||
| // Called from the USB interrupt when an isochronous packet arrives | |||||
| // we must completely remove it from the receive buffer before returning | |||||
| // | |||||
| static void rx_event(transfer_t *t) | static void rx_event(transfer_t *t) | ||||
| { | { | ||||
| int len = rx_max_size - ((t->status >> 16) & 0x7FFF); | |||||
| printf("rx event, len=%d\n", len); | |||||
| 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 | // TODO: actually move the data from USB to audio lib | ||||
| usb_audio_receive_callback(len); | |||||
| rx_queue_transfer(); | rx_queue_transfer(); | ||||
| } | } | ||||
| // Called from the USB interrupt when an isochronous packet arrives | |||||
| // we must completely remove it from the receive buffer before returning | |||||
| // | |||||
| #if 0 | |||||
| #if 1 | |||||
| void usb_audio_receive_callback(unsigned int len) | void usb_audio_receive_callback(unsigned int len) | ||||
| { | { | ||||
| unsigned int count, avail; | unsigned int count, avail; | ||||
| AudioInputUSB::receive_flag = 1; | AudioInputUSB::receive_flag = 1; | ||||
| len >>= 2; // 1 sample = 4 bytes: 2 left, 2 right | len >>= 2; // 1 sample = 4 bytes: 2 left, 2 right | ||||
| data = (const uint32_t *)usb_audio_receive_buffer; | |||||
| data = (const uint32_t *)rx_buffer; | |||||
| count = AudioInputUSB::incoming_count; | count = AudioInputUSB::incoming_count; | ||||
| left = AudioInputUSB::incoming_left; | left = AudioInputUSB::incoming_left; |
| 5, // bDescriptorType, 5 = ENDPOINT_DESCRIPTOR | 5, // bDescriptorType, 5 = ENDPOINT_DESCRIPTOR | ||||
| AUDIO_TX_ENDPOINT | 0x80, // bEndpointAddress | AUDIO_TX_ENDPOINT | 0x80, // bEndpointAddress | ||||
| 0x09, // bmAttributes = isochronous, adaptive | 0x09, // bmAttributes = isochronous, adaptive | ||||
| LSB(AUDIO_TX_SIZE_480), MSB(AUDIO_TX_SIZE_480), // wMaxPacketSize | |||||
| 1, // bInterval, 1 = every frame | |||||
| LSB(AUDIO_TX_SIZE), MSB(AUDIO_TX_SIZE), // wMaxPacketSize | |||||
| 4, // bInterval, 4 = every 8 micro-frames | |||||
| 0, // bRefresh | 0, // bRefresh | ||||
| 0, // bSynchAddress | 0, // bSynchAddress | ||||
| // Class-Specific AS Isochronous Audio Data Endpoint Descriptor | // Class-Specific AS Isochronous Audio Data Endpoint Descriptor | ||||
| 5, // bDescriptorType, 5 = ENDPOINT_DESCRIPTOR | 5, // bDescriptorType, 5 = ENDPOINT_DESCRIPTOR | ||||
| AUDIO_RX_ENDPOINT, // bEndpointAddress | AUDIO_RX_ENDPOINT, // bEndpointAddress | ||||
| 0x05, // bmAttributes = isochronous, asynchronous | 0x05, // bmAttributes = isochronous, asynchronous | ||||
| LSB(AUDIO_RX_SIZE_480), MSB(AUDIO_RX_SIZE_480), // wMaxPacketSize | |||||
| 1, // bInterval, 1 = every frame | |||||
| LSB(AUDIO_RX_SIZE), MSB(AUDIO_RX_SIZE), // wMaxPacketSize | |||||
| 4, // bInterval, 4 = every 8 micro-frames | |||||
| 0, // bRefresh | 0, // bRefresh | ||||
| AUDIO_SYNC_ENDPOINT | 0x80, // bSynchAddress | AUDIO_SYNC_ENDPOINT | 0x80, // bSynchAddress | ||||
| // Class-Specific AS Isochronous Audio Data Endpoint Descriptor | // Class-Specific AS Isochronous Audio Data Endpoint Descriptor | ||||
| AUDIO_SYNC_ENDPOINT | 0x80, // bEndpointAddress | AUDIO_SYNC_ENDPOINT | 0x80, // bEndpointAddress | ||||
| 0x11, // bmAttributes = isochronous, feedback | 0x11, // bmAttributes = isochronous, feedback | ||||
| 4, 0, // wMaxPacketSize, 4 bytes | 4, 0, // wMaxPacketSize, 4 bytes | ||||
| 1, // bInterval, 1 = every frame | |||||
| 4, // bInterval, 4 = 4 = every 8 micro-frames | |||||
| 5, // bRefresh, 5 = 32ms | 5, // bRefresh, 5 = 32ms | ||||
| 0, // bSynchAddress | 0, // bSynchAddress | ||||
| #endif | #endif | ||||
| 5, // bDescriptorType, 5 = ENDPOINT_DESCRIPTOR | 5, // bDescriptorType, 5 = ENDPOINT_DESCRIPTOR | ||||
| AUDIO_TX_ENDPOINT | 0x80, // bEndpointAddress | AUDIO_TX_ENDPOINT | 0x80, // bEndpointAddress | ||||
| 0x09, // bmAttributes = isochronous, adaptive | 0x09, // bmAttributes = isochronous, adaptive | ||||
| LSB(AUDIO_TX_SIZE_12), MSB(AUDIO_TX_SIZE_12), // wMaxPacketSize | |||||
| LSB(AUDIO_TX_SIZE), MSB(AUDIO_TX_SIZE), // wMaxPacketSize | |||||
| 1, // bInterval, 1 = every frame | 1, // bInterval, 1 = every frame | ||||
| 0, // bRefresh | 0, // bRefresh | ||||
| 0, // bSynchAddress | 0, // bSynchAddress | ||||
| 5, // bDescriptorType, 5 = ENDPOINT_DESCRIPTOR | 5, // bDescriptorType, 5 = ENDPOINT_DESCRIPTOR | ||||
| AUDIO_RX_ENDPOINT, // bEndpointAddress | AUDIO_RX_ENDPOINT, // bEndpointAddress | ||||
| 0x05, // bmAttributes = isochronous, asynchronous | 0x05, // bmAttributes = isochronous, asynchronous | ||||
| LSB(AUDIO_RX_SIZE_12), MSB(AUDIO_RX_SIZE_12), // wMaxPacketSize | |||||
| LSB(AUDIO_RX_SIZE), MSB(AUDIO_RX_SIZE), // wMaxPacketSize | |||||
| 1, // bInterval, 1 = every frame | 1, // bInterval, 1 = every frame | ||||
| 0, // bRefresh | 0, // bRefresh | ||||
| AUDIO_SYNC_ENDPOINT | 0x80, // bSynchAddress | AUDIO_SYNC_ENDPOINT | 0x80, // bSynchAddress |
| #define SEREMU_RX_INTERVAL 2 | #define SEREMU_RX_INTERVAL 2 | ||||
| #define AUDIO_INTERFACE 1 // Audio (uses 3 consecutive interfaces) | #define AUDIO_INTERFACE 1 // Audio (uses 3 consecutive interfaces) | ||||
| #define AUDIO_TX_ENDPOINT 3 | #define AUDIO_TX_ENDPOINT 3 | ||||
| #define AUDIO_TX_SIZE_12 180 | |||||
| #define AUDIO_TX_SIZE_480 24 | |||||
| #define AUDIO_TX_SIZE 180 | |||||
| //#define AUDIO_TX_SIZE_12 180 | |||||
| //#define AUDIO_TX_SIZE_480 24 | |||||
| #define AUDIO_RX_ENDPOINT 3 | #define AUDIO_RX_ENDPOINT 3 | ||||
| #define AUDIO_RX_SIZE_12 180 | |||||
| #define AUDIO_RX_SIZE_480 24 | |||||
| #define AUDIO_RX_SIZE 180 | |||||
| //#define AUDIO_RX_SIZE_12 180 | |||||
| //#define AUDIO_RX_SIZE_480 24 | |||||
| #define AUDIO_SYNC_ENDPOINT 4 | #define AUDIO_SYNC_ENDPOINT 4 | ||||
| #define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_INTERRUPT + ENDPOINT_TRANSMIT_INTERRUPT | #define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_INTERRUPT + ENDPOINT_TRANSMIT_INTERRUPT | ||||
| #define ENDPOINT3_CONFIG ENDPOINT_RECEIVE_ISOCHRONOUS + ENDPOINT_TRANSMIT_ISOCHRONOUS | #define ENDPOINT3_CONFIG ENDPOINT_RECEIVE_ISOCHRONOUS + ENDPOINT_TRANSMIT_ISOCHRONOUS |
| void usb_config_rx(uint32_t ep, uint32_t packet_size, int do_zlp, void (*cb)(transfer_t *)); | void usb_config_rx(uint32_t ep, uint32_t packet_size, int do_zlp, void (*cb)(transfer_t *)); | ||||
| void usb_config_tx(uint32_t ep, uint32_t packet_size, int do_zlp, void (*cb)(transfer_t *)); | void usb_config_tx(uint32_t ep, uint32_t packet_size, int do_zlp, void (*cb)(transfer_t *)); | ||||
| void usb_config_rx_iso(uint32_t ep, uint32_t packet_size, int mult, void (*cb)(transfer_t *)); | |||||
| void usb_config_tx_iso(uint32_t ep, uint32_t packet_size, int mult, void (*cb)(transfer_t *)); | |||||
| void usb_prepare_transfer(transfer_t *transfer, const void *data, uint32_t len, uint32_t param); | void usb_prepare_transfer(transfer_t *transfer, const void *data, uint32_t len, uint32_t param); | ||||
| void usb_transmit(int endpoint_number, transfer_t *transfer); | void usb_transmit(int endpoint_number, transfer_t *transfer); |