瀏覽代碼

USB audio on Teensy 4.0 (work in progress)

main
PaulStoffregen 4 年之前
父節點
當前提交
011cd8985c
共有 7 個文件被更改,包括 691 次插入17 次删除
  1. +1
    -1
      teensy4/WProgram.h
  2. +60
    -0
      teensy4/usb.c
  3. +501
    -0
      teensy4/usb_audio.cpp
  4. +107
    -0
      teensy4/usb_audio.h
  5. +5
    -5
      teensy4/usb_desc.c
  6. +10
    -10
      teensy4/usb_desc.h
  7. +7
    -1
      teensy4/usb_dev.h

+ 1
- 1
teensy4/WProgram.h 查看文件

@@ -57,7 +57,7 @@
#include "usb_rawhid.h"
#include "usb_flightsim.h"
//#include "usb_mtp.h"
//#include "usb_audio.h"
#include "usb_audio.h"
#include "usb_touch.h"
//#include "usb_undef.h" // do not allow usb_desc.h stuff to leak to user programs


+ 60
- 0
teensy4/usb.c 查看文件

@@ -9,6 +9,7 @@
#include "usb_flightsim.h"
#include "usb_touch.h"
#include "usb_midi.h"
#include "usb_audio.h"
#include "core_pins.h" // for delay()
#include "avr/pgmspace.h"
#include <string.h>
@@ -421,6 +422,9 @@ static void endpoint0_setup(uint64_t setupdata)
#if defined(MIDI_INTERFACE)
usb_midi_configure();
#endif
#if defined(AUDIO_INTERFACE)
usb_audio_configure();
#endif
endpoint0_receive(NULL, 0, 0);
return;
case 0x0880: // GET_CONFIGURATION
@@ -525,6 +529,59 @@ static void endpoint0_setup(uint64_t setupdata)
return;
}
break;
#endif
#if defined(AUDIO_INTERFACE)
case 0x0B01: // SET_INTERFACE (alternate setting)
if (setup.wIndex == AUDIO_INTERFACE+1) {
usb_audio_transmit_setting = setup.wValue;
if (usb_audio_transmit_setting > 0) {
// TODO: set up AUDIO_TX_ENDPOINT to transmit
}
endpoint0_receive(NULL, 0, 0);
return;
} else if (setup.wIndex == AUDIO_INTERFACE+2) {
usb_audio_receive_setting = setup.wValue;
endpoint0_receive(NULL, 0, 0);
return;
}
break;
case 0x0A81: // GET_INTERFACE (alternate setting)
if (setup.wIndex == AUDIO_INTERFACE+1) {
endpoint0_buffer[0] = usb_audio_transmit_setting;
endpoint0_transmit(endpoint0_buffer, 1, 0);
return;
} else if (setup.wIndex == AUDIO_INTERFACE+2) {
endpoint0_buffer[0] = usb_audio_receive_setting;
endpoint0_transmit(endpoint0_buffer, 1, 0);
return;
}
break;
case 0x0121: // SET FEATURE
case 0x0221:
case 0x0321:
case 0x0421:
endpoint0_receive(NULL, 0, 1); // handle these after ACK
return;
case 0x81A1: // GET FEATURE
case 0x82A1:
case 0x83A1:
case 0x84A1:
if (setup.wLength <= sizeof(endpoint0_buffer)) {
/*if (usb_audio_get_feature(&setup, endpoint0_buffer, setup.wLength)) {
endpoint0_transmit(endpoint0_buffer, setup.wLength, 0);
return;
}*/
}
break;
case 0x81A2: // GET_CUR (wValue=0, wIndex=interface, wLength=len)
if (setup.wLength >= 3) {
endpoint0_buffer[0] = 44100 & 255;
endpoint0_buffer[1] = 44100 >> 8;
endpoint0_buffer[2] = 0;
endpoint0_transmit(endpoint0_buffer, 3, 0);
return;
}
break;
#endif
}
USB1_ENDPTCTRL0 = 0x000010001; // stall
@@ -642,6 +699,9 @@ static void endpoint0_complete(void)
usb_reboot_timer = 80; // TODO: 10 if only 12 Mbit/sec
}
#endif
#ifdef AUDIO_INTERFACE
// TODO: usb_audio_set_feature()
#endif
}

static void usb_endpoint_config(endpoint_t *qh, uint32_t config, void (*callback)(transfer_t *))

+ 501
- 0
teensy4/usb_audio.cpp 查看文件

@@ -0,0 +1,501 @@
/* Teensyduino Core Library
* http://www.pjrc.com/teensy/
* Copyright (c) 2017 PJRC.COM, LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* 1. The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* 2. If the Software is incorporated into a build system that allows
* selection among a list of target devices, then similar target
* devices manufactured by PJRC.COM must be included in the list of
* target devices and selectable in the same manner.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

#include <Arduino.h>
#include "usb_dev.h"
#include "debug/printf.h"

#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;
audio_block_t * AudioInputUSB::incoming_left;
audio_block_t * AudioInputUSB::incoming_right;
audio_block_t * AudioInputUSB::ready_left;
audio_block_t * AudioInputUSB::ready_right;
uint16_t AudioInputUSB::incoming_count;
uint8_t AudioInputUSB::receive_flag;

struct usb_audio_features_struct AudioInputUSB::features = {0,0,FEATURE_MAX_VOLUME/2};

extern volatile uint8_t usb_high_speed;
static void rx_event(transfer_t *t);

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;

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

uint8_t usb_audio_receive_setting=0;
uint8_t usb_audio_transmit_setting=0;

static uint32_t feedback_accumulator = 185042824;


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_receive(AUDIO_RX_ENDPOINT, &rx_transfer);
}


void usb_audio_configure(void)
{
printf("usb_audio_configure\n");
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);
rx_queue_transfer();
}



void AudioInputUSB::begin(void)
{
incoming_count = 0;
incoming_left = NULL;
incoming_right = NULL;
ready_left = NULL;
ready_right = NULL;
receive_flag = 0;
// update_responsibility = update_setup();
// TODO: update responsibility is tough, partly because the USB
// interrupts aren't sychronous to the audio library block size,
// but also because the PC may stop transmitting data, which
// means we no longer get receive callbacks from usb.c
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)
{
uint32_t *target = (uint32_t*) src + len;
while ((src < target) && (((uintptr_t) left & 0x02) != 0)) {
uint32_t n = *src++;
*left++ = n & 0xFFFF;
*right++ = n >> 16;
}

while ((src < target - 2)) {
uint32_t n1 = *src++;
uint32_t n = *src++;
*(uint32_t *)left = (n1 & 0xFFFF) | ((n & 0xFFFF) << 16);
left+=2;
*(uint32_t *)right = (n1 >> 16) | ((n & 0xFFFF0000)) ;
right+=2;
}

while ((src < target)) {
uint32_t n = *src++;
*left++ = n & 0xFFFF;
*right++ = n >> 16;
}
}

static void rx_event(transfer_t *t)
{
int len = rx_max_size - ((t->status >> 16) & 0x7FFF);
printf("rx event, len=%d\n", len);
// TODO: actually move the data from USB to audio lib
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
void usb_audio_receive_callback(unsigned int len)
{
unsigned int count, avail;
audio_block_t *left, *right;
const uint32_t *data;

AudioInputUSB::receive_flag = 1;
len >>= 2; // 1 sample = 4 bytes: 2 left, 2 right
data = (const uint32_t *)usb_audio_receive_buffer;

count = AudioInputUSB::incoming_count;
left = AudioInputUSB::incoming_left;
right = AudioInputUSB::incoming_right;
if (left == NULL) {
left = AudioStream::allocate();
if (left == NULL) return;
AudioInputUSB::incoming_left = left;
}
if (right == NULL) {
right = AudioStream::allocate();
if (right == NULL) return;
AudioInputUSB::incoming_right = right;
}
while (len > 0) {
avail = AUDIO_BLOCK_SAMPLES - count;
if (len < avail) {
copy_to_buffers(data, left->data + count, right->data + count, len);
AudioInputUSB::incoming_count = count + len;
return;
} else if (avail > 0) {
copy_to_buffers(data, left->data + count, right->data + count, avail);
data += avail;
len -= avail;
if (AudioInputUSB::ready_left || AudioInputUSB::ready_right) {
// buffer overrun, PC sending too fast
AudioInputUSB::incoming_count = count + avail;
//if (len > 0) {
//serial_print("!");
//serial_phex(len);
//}
return;
}
send:
AudioInputUSB::ready_left = left;
AudioInputUSB::ready_right = right;
//if (AudioInputUSB::update_responsibility) AudioStream::update_all();
left = AudioStream::allocate();
if (left == NULL) {
AudioInputUSB::incoming_left = NULL;
AudioInputUSB::incoming_right = NULL;
AudioInputUSB::incoming_count = 0;
return;
}
right = AudioStream::allocate();
if (right == NULL) {
AudioStream::release(left);
AudioInputUSB::incoming_left = NULL;
AudioInputUSB::incoming_right = NULL;
AudioInputUSB::incoming_count = 0;
return;
}
AudioInputUSB::incoming_left = left;
AudioInputUSB::incoming_right = right;
count = 0;
} else {
if (AudioInputUSB::ready_left || AudioInputUSB::ready_right) return;
goto send; // recover from buffer overrun
}
}
AudioInputUSB::incoming_count = count;
}
#endif

void AudioInputUSB::update(void)
{
audio_block_t *left, *right;

__disable_irq();
left = ready_left;
ready_left = NULL;
right = ready_right;
ready_right = NULL;
uint16_t c = incoming_count;
uint8_t f = receive_flag;
receive_flag = 0;
__enable_irq();
if (f) {
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
//usb_audio_sync_feedback = feedback;
//if (diff > 0) {
//serial_print(".");
//} else if (diff < 0) {
//serial_print("^");
//}
}
//serial_phex(c);
//serial_print(".");
if (!left || !right) {
//serial_print("#"); // buffer underrun - PC sending too slow
//if (f) feedback_accumulator += 10 << 8;
}
if (left) {
transmit(left, 0);
release(left);
}
if (right) {
transmit(right, 1);
release(right);
}
}



















#if 0
bool AudioOutputUSB::update_responsibility;
audio_block_t * AudioOutputUSB::left_1st;
audio_block_t * AudioOutputUSB::left_2nd;
audio_block_t * AudioOutputUSB::right_1st;
audio_block_t * AudioOutputUSB::right_2nd;
uint16_t AudioOutputUSB::offset_1st;


uint16_t usb_audio_transmit_buffer[AUDIO_TX_SIZE/2] DMABUFATTR;

void AudioOutputUSB::begin(void)
{
update_responsibility = false;
left_1st = NULL;
right_1st = NULL;
}

static void copy_from_buffers(uint32_t *dst, int16_t *left, int16_t *right, unsigned int len)
{
// TODO: optimize...
while (len > 0) {
*dst++ = (*right++ << 16) | (*left++ & 0xFFFF);
len--;
}
}

void AudioOutputUSB::update(void)
{
audio_block_t *left, *right;

// TODO: we shouldn't be writing to these......
//left = receiveReadOnly(0); // input 0 = left channel
//right = receiveReadOnly(1); // input 1 = right channel
left = receiveWritable(0); // input 0 = left channel
right = receiveWritable(1); // input 1 = right channel
if (usb_audio_transmit_setting == 0) {
if (left) release(left);
if (right) release(right);
if (left_1st) { release(left_1st); left_1st = NULL; }
if (left_2nd) { release(left_2nd); left_2nd = NULL; }
if (right_1st) { release(right_1st); right_1st = NULL; }
if (right_2nd) { release(right_2nd); right_2nd = NULL; }
offset_1st = 0;
return;
}
if (left == NULL) {
left = allocate();
if (left == NULL) {
if (right) release(right);
return;
}
memset(left->data, 0, sizeof(left->data));
}
if (right == NULL) {
right = allocate();
if (right == NULL) {
release(left);
return;
}
memset(right->data, 0, sizeof(right->data));
}
__disable_irq();
if (left_1st == NULL) {
left_1st = left;
right_1st = right;
offset_1st = 0;
} else if (left_2nd == NULL) {
left_2nd = left;
right_2nd = right;
} else {
// buffer overrun - PC is consuming too slowly
audio_block_t *discard1 = left_1st;
left_1st = left_2nd;
left_2nd = left;
audio_block_t *discard2 = right_1st;
right_1st = right_2nd;
right_2nd = right;
offset_1st = 0; // TODO: discard part of this data?
//serial_print("*");
release(discard1);
release(discard2);
}
__enable_irq();
}


// Called from the USB interrupt when ready to transmit another
// isochronous packet. If we place data into the transmit buffer,
// the return is the number of bytes. Otherwise, return 0 means
// no data to transmit
unsigned int usb_audio_transmit_callback(void)
{
static uint32_t count=5;
uint32_t avail, num, target, offset, len=0;
audio_block_t *left, *right;

if (++count < 9) { // TODO: dynamic adjust to match USB rate
target = 44;
} else {
count = 0;
target = 45;
}
while (len < target) {
num = target - len;
left = AudioOutputUSB::left_1st;
if (left == NULL) {
// buffer underrun - PC is consuming too quickly
memset(usb_audio_transmit_buffer + len, 0, num * 4);
//serial_print("%");
break;
}
right = AudioOutputUSB::right_1st;
offset = AudioOutputUSB::offset_1st;

avail = AUDIO_BLOCK_SAMPLES - offset;
if (num > avail) num = avail;

copy_from_buffers((uint32_t *)usb_audio_transmit_buffer + len,
left->data + offset, right->data + offset, num);
len += num;
offset += num;
if (offset >= AUDIO_BLOCK_SAMPLES) {
AudioStream::release(left);
AudioStream::release(right);
AudioOutputUSB::left_1st = AudioOutputUSB::left_2nd;
AudioOutputUSB::left_2nd = NULL;
AudioOutputUSB::right_1st = AudioOutputUSB::right_2nd;
AudioOutputUSB::right_2nd = NULL;
AudioOutputUSB::offset_1st = 0;
} else {
AudioOutputUSB::offset_1st = offset;
}
}
return target * 4;
}
#endif




struct setup_struct {
union {
struct {
uint8_t bmRequestType;
uint8_t bRequest;
union {
struct {
uint8_t bChannel; // 0=main, 1=left, 2=right
uint8_t bCS; // Control Selector
};
uint16_t wValue;
};
union {
struct {
uint8_t bIfEp; // type of entity
uint8_t bEntityId; // UnitID, TerminalID, etc.
};
uint16_t wIndex;
};
uint16_t wLength;
};
};
};

int usb_audio_get_feature(void *stp, uint8_t *data, uint32_t *datalen)
{
struct setup_struct setup = *((struct setup_struct *)stp);
if (setup.bmRequestType==0xA1) { // should check bRequest, bChannel, and UnitID
if (setup.bCS==0x01) { // mute
data[0] = AudioInputUSB::features.mute; // 1=mute, 0=unmute
*datalen = 1;
return 1;
}
else if (setup.bCS==0x02) { // volume
if (setup.bRequest==0x81) { // GET_CURR
data[0] = AudioInputUSB::features.volume & 0xFF;
data[1] = (AudioInputUSB::features.volume>>8) & 0xFF;
}
else if (setup.bRequest==0x82) { // GET_MIN
//serial_print("vol get_min\n");
data[0] = 0; // min level is 0
data[1] = 0;
}
else if (setup.bRequest==0x83) { // GET_MAX
data[0] = FEATURE_MAX_VOLUME & 0xFF; // max level, for range of 0 to MAX
data[1] = (FEATURE_MAX_VOLUME>>8) & 0x0F;
}
else if (setup.bRequest==0x84) { // GET_RES
data[0] = 1; // increment vol by by 1
data[1] = 0;
}
else { // pass over SET_MEM, etc.
return 0;
}
*datalen = 2;
return 1;
}
}
return 0;
}

int usb_audio_set_feature(void *stp, uint8_t *buf)
{
struct setup_struct setup = *((struct setup_struct *)stp);
if (setup.bmRequestType==0x21) { // should check bRequest, bChannel and UnitID
if (setup.bCS==0x01) { // mute
if (setup.bRequest==0x01) { // SET_CUR
AudioInputUSB::features.mute = buf[0]; // 1=mute,0=unmute
AudioInputUSB::features.change = 1;
return 1;
}
}
else if (setup.bCS==0x02) { // volume
if (setup.bRequest==0x01) { // SET_CUR
AudioInputUSB::features.volume = buf[0] + (buf[1]<<8);
AudioInputUSB::features.change = 1;
return 1;
}
}
}
return 0;
}


#endif // AUDIO_INTERFACE

+ 107
- 0
teensy4/usb_audio.h 查看文件

@@ -0,0 +1,107 @@
/* Teensyduino Core Library
* http://www.pjrc.com/teensy/
* Copyright (c) 2017 PJRC.COM, LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* 1. The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* 2. If the Software is incorporated into a build system that allows
* selection among a list of target devices, then similar target
* devices manufactured by PJRC.COM must be included in the list of
* target devices and selectable in the same manner.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

#pragma once

#include "usb_desc.h"
#ifdef AUDIO_INTERFACE

#define FEATURE_MAX_VOLUME 0xFFF // volume accepted from 0 to 0xFFF

#ifdef __cplusplus
extern "C" {
#endif
extern void usb_audio_configure();
extern uint16_t usb_audio_receive_buffer[];
extern uint16_t usb_audio_transmit_buffer[];
extern uint32_t usb_audio_sync_feedback;
extern uint8_t usb_audio_receive_setting;
extern uint8_t usb_audio_transmit_setting;
extern void usb_audio_receive_callback(unsigned int len);
extern unsigned int usb_audio_transmit_callback(void);
extern int usb_audio_set_feature(void *stp, uint8_t *buf);
extern int usb_audio_get_feature(void *stp, uint8_t *data, uint32_t *datalen);
#ifdef __cplusplus
}
#endif

// audio features supported
struct usb_audio_features_struct {
int change; // set to 1 when any value is changed
int mute; // 1=mute, 0=unmute
int volume; // volume from 0 to FEATURE_MAX_VOLUME, maybe should be float from 0.0 to 1.0
};

#ifdef __cplusplus
#include "AudioStream.h"

class AudioInputUSB : public AudioStream
{
public:
AudioInputUSB(void) : AudioStream(0, NULL) { begin(); }
virtual void update(void);
void begin(void);
friend void usb_audio_receive_callback(unsigned int len);
friend int usb_audio_set_feature(void *stp, uint8_t *buf);
friend int usb_audio_get_feature(void *stp, uint8_t *data, uint32_t *datalen);
static struct usb_audio_features_struct features;
float volume(void) {
if (features.mute) return 0.0;
return (float)(features.volume) * (1.0 / (float)FEATURE_MAX_VOLUME);
}
private:
static bool update_responsibility;
static audio_block_t *incoming_left;
static audio_block_t *incoming_right;
static audio_block_t *ready_left;
static audio_block_t *ready_right;
static uint16_t incoming_count;
static uint8_t receive_flag;
};

class AudioOutputUSB : public AudioStream
{
public:
AudioOutputUSB(void) : AudioStream(2, inputQueueArray) { begin(); }
virtual void update(void);
void begin(void);
friend unsigned int usb_audio_transmit_callback(void);
private:
static bool update_responsibility;
static audio_block_t *left_1st;
static audio_block_t *left_2nd;
static audio_block_t *right_1st;
static audio_block_t *right_2nd;
static uint16_t offset_1st;
audio_block_t *inputQueueArray[2];
};
#endif // __cplusplus

#endif // AUDIO_INTERFACE

+ 5
- 5
teensy4/usb_desc.c 查看文件

@@ -1321,7 +1321,7 @@ PROGMEM const uint8_t usb_config_descriptor_480[CONFIG_DESC_SIZE] = {
5, // bDescriptorType, 5 = ENDPOINT_DESCRIPTOR
AUDIO_TX_ENDPOINT | 0x80, // bEndpointAddress
0x09, // bmAttributes = isochronous, adaptive
LSB(AUDIO_TX_SIZE), MSB(AUDIO_TX_SIZE), // wMaxPacketSize
LSB(AUDIO_TX_SIZE_480), MSB(AUDIO_TX_SIZE_480), // wMaxPacketSize
1, // bInterval, 1 = every frame
0, // bRefresh
0, // bSynchAddress
@@ -1380,7 +1380,7 @@ PROGMEM const uint8_t usb_config_descriptor_480[CONFIG_DESC_SIZE] = {
5, // bDescriptorType, 5 = ENDPOINT_DESCRIPTOR
AUDIO_RX_ENDPOINT, // bEndpointAddress
0x05, // bmAttributes = isochronous, asynchronous
LSB(AUDIO_RX_SIZE), MSB(AUDIO_RX_SIZE), // wMaxPacketSize
LSB(AUDIO_RX_SIZE_480), MSB(AUDIO_RX_SIZE_480), // wMaxPacketSize
1, // bInterval, 1 = every frame
0, // bRefresh
AUDIO_SYNC_ENDPOINT | 0x80, // bSynchAddress
@@ -1398,7 +1398,7 @@ PROGMEM const uint8_t usb_config_descriptor_480[CONFIG_DESC_SIZE] = {
5, // bDescriptorType, 5 = ENDPOINT_DESCRIPTOR
AUDIO_SYNC_ENDPOINT | 0x80, // bEndpointAddress
0x11, // bmAttributes = isochronous, feedback
3, 0, // wMaxPacketSize, 3 bytes
4, 0, // wMaxPacketSize, 4 bytes
1, // bInterval, 1 = every frame
5, // bRefresh, 5 = 32ms
0, // bSynchAddress
@@ -2155,7 +2155,7 @@ PROGMEM const uint8_t usb_config_descriptor_12[CONFIG_DESC_SIZE] = {
5, // bDescriptorType, 5 = ENDPOINT_DESCRIPTOR
AUDIO_TX_ENDPOINT | 0x80, // bEndpointAddress
0x09, // bmAttributes = isochronous, adaptive
LSB(AUDIO_TX_SIZE), MSB(AUDIO_TX_SIZE), // wMaxPacketSize
LSB(AUDIO_TX_SIZE_12), MSB(AUDIO_TX_SIZE_12), // wMaxPacketSize
1, // bInterval, 1 = every frame
0, // bRefresh
0, // bSynchAddress
@@ -2214,7 +2214,7 @@ PROGMEM const uint8_t usb_config_descriptor_12[CONFIG_DESC_SIZE] = {
5, // bDescriptorType, 5 = ENDPOINT_DESCRIPTOR
AUDIO_RX_ENDPOINT, // bEndpointAddress
0x05, // bmAttributes = isochronous, asynchronous
LSB(AUDIO_RX_SIZE), MSB(AUDIO_RX_SIZE), // wMaxPacketSize
LSB(AUDIO_RX_SIZE_12), MSB(AUDIO_RX_SIZE_12), // wMaxPacketSize
1, // bInterval, 1 = every frame
0, // bRefresh
AUDIO_SYNC_ENDPOINT | 0x80, // bSynchAddress

+ 10
- 10
teensy4/usb_desc.h 查看文件

@@ -645,7 +645,7 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports
#define NUM_ENDPOINTS 5
#define NUM_INTERFACE 4
#define SEREMU_INTERFACE 0 // Serial emulation
#define SEREMU_TX_ENDPOINT 1
#define SEREMU_TX_ENDPOINT 2
#define SEREMU_TX_SIZE 64
#define SEREMU_TX_INTERVAL 1
#define SEREMU_RX_ENDPOINT 2
@@ -653,15 +653,15 @@ let me know? http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports
#define SEREMU_RX_INTERVAL 2
#define AUDIO_INTERFACE 1 // Audio (uses 3 consecutive interfaces)
#define AUDIO_TX_ENDPOINT 3
#define AUDIO_TX_SIZE 180
#define AUDIO_RX_ENDPOINT 4
#define AUDIO_RX_SIZE 180
#define AUDIO_SYNC_ENDPOINT 5
#define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY
#define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ISOCHRONOUS
#define ENDPOINT4_CONFIG ENDPOINT_RECEIVE_ISOCHRONOUS
#define ENDPOINT5_CONFIG ENDPOINT_TRANSMIT_ISOCHRONOUS
#define AUDIO_TX_SIZE_12 180
#define AUDIO_TX_SIZE_480 24
#define AUDIO_RX_ENDPOINT 3
#define AUDIO_RX_SIZE_12 180
#define AUDIO_RX_SIZE_480 24
#define AUDIO_SYNC_ENDPOINT 4
#define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_INTERRUPT + ENDPOINT_TRANSMIT_INTERRUPT
#define ENDPOINT3_CONFIG ENDPOINT_RECEIVE_ISOCHRONOUS + ENDPOINT_TRANSMIT_ISOCHRONOUS
#define ENDPOINT4_CONFIG ENDPOINT_TRANSMIT_ISOCHRONOUS

#elif defined(USB_MIDI_AUDIO_SERIAL)
#define VENDOR_ID 0x16C0

+ 7
- 1
teensy4/usb_dev.h 查看文件

@@ -13,6 +13,10 @@ struct transfer_struct {
uint32_t callback_param;
};

#ifdef __cplusplus
extern "C" {
#endif

void usb_init(void);
void usb_init_serialnumber(void);

@@ -30,4 +34,6 @@ void usb_stop_sof_interrupts(int interface);
extern void (*usb_timer0_callback)(void);
extern void (*usb_timer1_callback)(void);


#ifdef __cplusplus
}
#endif

Loading…
取消
儲存