Browse Source

USB audio on Teensy 4.0 (more work in progress)

teensy4-core
PaulStoffregen 4 years ago
parent
commit
0cde58d99f
5 changed files with 47 additions and 32 deletions
  1. +18
    -0
      teensy4/usb.c
  2. +14
    -21
      teensy4/usb_audio.cpp
  3. +7
    -7
      teensy4/usb_desc.c
  4. +6
    -4
      teensy4/usb_desc.h
  5. +2
    -0
      teensy4/usb_dev.h

+ 18
- 0
teensy4/usb.c View File

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)

+ 14
- 21
teensy4/usb_audio.cpp View File



#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;

+ 7
- 7
teensy4/usb_desc.c View File

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

+ 6
- 4
teensy4/usb_desc.h View File

#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

+ 2
- 0
teensy4/usb_dev.h View File



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);

Loading…
Cancel
Save