RP2040 New ISO API
This commit is contained in:
@@ -1307,7 +1307,7 @@ uint16_t videod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin
|
|||||||
#ifdef TUP_DCD_EDPT_ISO_ALLOC
|
#ifdef TUP_DCD_EDPT_ISO_ALLOC
|
||||||
/* Allocate ISO endpoints */
|
/* Allocate ISO endpoints */
|
||||||
uint16_t ep_size = 0;
|
uint16_t ep_size = 0;
|
||||||
uint16_t ep_addr = 0;
|
uint8_t ep_addr = 0;
|
||||||
uint8_t const *p_desc = (uint8_t const*)itf_desc + stm->desc.beg;
|
uint8_t const *p_desc = (uint8_t const*)itf_desc + stm->desc.beg;
|
||||||
uint8_t const *p_desc_end = (uint8_t const*)itf_desc + stm->desc.end;
|
uint8_t const *p_desc_end = (uint8_t const*)itf_desc + stm->desc.end;
|
||||||
while (p_desc < p_desc_end) {
|
while (p_desc < p_desc_end) {
|
||||||
|
@@ -366,6 +366,7 @@
|
|||||||
// Raspberry Pi
|
// Raspberry Pi
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
#elif TU_CHECK_MCU(OPT_MCU_RP2040)
|
#elif TU_CHECK_MCU(OPT_MCU_RP2040)
|
||||||
|
#define TUP_DCD_EDPT_ISO_ALLOC
|
||||||
#define TUP_DCD_ENDPOINT_MAX 16
|
#define TUP_DCD_ENDPOINT_MAX 16
|
||||||
|
|
||||||
#define TU_ATTR_FAST_FUNC __attribute__((section(".time_critical.tinyusb")))
|
#define TU_ATTR_FAST_FUNC __attribute__((section(".time_critical.tinyusb")))
|
||||||
|
@@ -46,9 +46,11 @@
|
|||||||
/*------------------------------------------------------------------*/
|
/*------------------------------------------------------------------*/
|
||||||
/* Low level controller
|
/* Low level controller
|
||||||
*------------------------------------------------------------------*/
|
*------------------------------------------------------------------*/
|
||||||
|
static void hw_endpoint_init(uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t transfer_type);
|
||||||
|
static void hw_set_endpoint_control_reg(struct hw_endpoint* ep, uint dpram_offset);
|
||||||
|
|
||||||
// Init these in dcd_init
|
// Init these in dcd_init
|
||||||
static uint8_t* next_buffer_ptr;
|
static uint8_t* next_buffer_ptr = NULL;
|
||||||
|
|
||||||
// USB_MAX_ENDPOINTS Endpoints, direction TUSB_DIR_OUT for out and TUSB_DIR_IN for in.
|
// USB_MAX_ENDPOINTS Endpoints, direction TUSB_DIR_OUT for out and TUSB_DIR_IN for in.
|
||||||
static struct hw_endpoint hw_endpoints[USB_MAX_ENDPOINTS][2];
|
static struct hw_endpoint hw_endpoints[USB_MAX_ENDPOINTS][2];
|
||||||
@@ -66,31 +68,82 @@ TU_ATTR_ALWAYS_INLINE static inline struct hw_endpoint* hw_endpoint_get_by_addr(
|
|||||||
return hw_endpoint_get_by_num(num, dir);
|
return hw_endpoint_get_by_num(num, dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _hw_endpoint_alloc(struct hw_endpoint* ep, uint8_t transfer_type) {
|
// Allocate from the USB buffer space (max 3840 bytes)
|
||||||
|
static void hw_endpoint_alloc(struct hw_endpoint* ep, size_t size) {
|
||||||
|
static uint8_t *end;
|
||||||
|
// determine buffer end
|
||||||
|
if (end == NULL){
|
||||||
|
end = &usb_dpram->epx_data[0] + 0xF00;
|
||||||
|
}
|
||||||
|
// determine first next_buffer_ptr if necessary
|
||||||
|
if (next_buffer_ptr == NULL){
|
||||||
|
next_buffer_ptr = &usb_dpram->epx_data[0];
|
||||||
|
}
|
||||||
|
// assign buffer
|
||||||
|
ep->hw_data_buf = next_buffer_ptr;
|
||||||
|
next_buffer_ptr += size;
|
||||||
|
|
||||||
|
hard_assert(next_buffer_ptr < end);
|
||||||
|
|
||||||
|
pico_info(" Allocated %d bytes (0x%p)\r\n", size, ep->hw_data_buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
// allocate endpoint and fill endpoint control registers
|
||||||
|
static void hw_endpoint_alloc_and_control(struct hw_endpoint* ep, uint8_t transfer_type) {
|
||||||
// size must be multiple of 64
|
// size must be multiple of 64
|
||||||
uint size = tu_div_ceil(ep->wMaxPacketSize, 64) * 64u;
|
uint size = tu_div_ceil(ep->wMaxPacketSize, 64) * 64u;
|
||||||
|
|
||||||
// double buffered Bulk endpoint
|
// double buffered Bulk endpoint
|
||||||
if (transfer_type == TUSB_XFER_BULK) {
|
if (transfer_type == TUSB_XFER_BULK) {
|
||||||
size *= 2u;
|
size *= 2u;
|
||||||
}
|
}
|
||||||
|
ep->transfer_type = transfer_type;
|
||||||
|
hw_endpoint_alloc(ep, size);
|
||||||
|
|
||||||
ep->hw_data_buf = next_buffer_ptr;
|
|
||||||
next_buffer_ptr += size;
|
|
||||||
|
|
||||||
assert(((uintptr_t) next_buffer_ptr & 0b111111u) == 0);
|
|
||||||
uint dpram_offset = hw_data_offset(ep->hw_data_buf);
|
uint dpram_offset = hw_data_offset(ep->hw_data_buf);
|
||||||
hard_assert(hw_data_offset(next_buffer_ptr) <= USB_DPRAM_MAX);
|
|
||||||
|
|
||||||
pico_info(" Allocated %d bytes at offset 0x%x (0x%p)\r\n", size, dpram_offset, ep->hw_data_buf);
|
pico_info(" Allocated %d bytes at offset 0x%x (0x%p)\r\n", size, dpram_offset, ep->hw_data_buf);
|
||||||
|
|
||||||
// Fill in endpoint control register with buffer offset
|
hw_set_endpoint_control_reg(ep, dpram_offset);
|
||||||
uint32_t const reg = EP_CTRL_ENABLE_BITS | ((uint) transfer_type << EP_CTRL_BUFFER_TYPE_LSB) | dpram_offset;
|
}
|
||||||
|
|
||||||
|
static void hw_set_endpoint_control_reg(struct hw_endpoint* ep, uint dpram_offset) {
|
||||||
|
// Fill in endpoint control register with buffer offset
|
||||||
|
uint32_t const reg = EP_CTRL_ENABLE_BITS | ((uint) ep->transfer_type << EP_CTRL_BUFFER_TYPE_LSB) | dpram_offset;
|
||||||
*ep->endpoint_control = reg;
|
*ep->endpoint_control = reg;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _hw_endpoint_close(struct hw_endpoint* ep) {
|
// New API: Allocate packet buffer used by ISO endpoints
|
||||||
|
// Some MCU need manual packet buffer allocation, we allocate the largest size to avoid clustering
|
||||||
|
bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) {
|
||||||
|
(void) rhport;
|
||||||
|
assert(rhport == 0);
|
||||||
|
struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_addr);
|
||||||
|
// size must be multiple of 64
|
||||||
|
uint16_t size = (uint16_t)tu_div_ceil(largest_packet_size, 64) * 64u;
|
||||||
|
ep->wMaxPacketSize = size;
|
||||||
|
hw_endpoint_alloc(ep, size);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// New API: Configure and enable an ISO endpoint according to descriptor
|
||||||
|
bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc) {
|
||||||
|
(void) rhport;
|
||||||
|
assert(rhport == 0);
|
||||||
|
const uint8_t ep_addr = ep_desc->bEndpointAddress;
|
||||||
|
const uint16_t mps = ep_desc->wMaxPacketSize;
|
||||||
|
uint16_t size = (uint16_t)tu_div_ceil(mps, 64) * 64u;
|
||||||
|
|
||||||
|
// init w/o allocate
|
||||||
|
hw_endpoint_init(ep_addr, size, TUSB_XFER_ISOCHRONOUS);
|
||||||
|
|
||||||
|
// Fill in endpoint control register with buffer offset
|
||||||
|
struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_addr);
|
||||||
|
uint dpram_offset = hw_data_offset(ep->hw_data_buf);
|
||||||
|
hw_set_endpoint_control_reg(ep, dpram_offset);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hw_endpoint_close(uint8_t ep_addr) {
|
||||||
|
struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_addr);
|
||||||
// Clear hardware registers and then zero the struct
|
// Clear hardware registers and then zero the struct
|
||||||
// Clears endpoint enable
|
// Clears endpoint enable
|
||||||
*ep->endpoint_control = 0;
|
*ep->endpoint_control = 0;
|
||||||
@@ -113,11 +166,20 @@ static void _hw_endpoint_close(struct hw_endpoint* ep) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hw_endpoint_close(uint8_t ep_addr) {
|
// Legacy init called by dcd_init (which does allocation)
|
||||||
|
static void hw_endpoint_init_and_alloc(uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t transfer_type) {
|
||||||
struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_addr);
|
struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_addr);
|
||||||
_hw_endpoint_close(ep);
|
uint16_t size = (uint16_t) tu_div_ceil(wMaxPacketSize, 64) * 64u;
|
||||||
|
// size must be multiple of 64
|
||||||
|
hw_endpoint_init(ep_addr, size, transfer_type);
|
||||||
|
const uint8_t num = tu_edpt_number(ep_addr);
|
||||||
|
if (num != 0) {
|
||||||
|
// alloc a buffer and fill in endpoint control register
|
||||||
|
hw_endpoint_alloc_and_control(ep, transfer_type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// main processing for dcd_edpt_iso_activate
|
||||||
static void hw_endpoint_init(uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t transfer_type) {
|
static void hw_endpoint_init(uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t transfer_type) {
|
||||||
struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_addr);
|
struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_addr);
|
||||||
|
|
||||||
@@ -156,9 +218,6 @@ static void hw_endpoint_init(uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t t
|
|||||||
} else {
|
} else {
|
||||||
ep->endpoint_control = &usb_dpram->ep_ctrl[num - 1].out;
|
ep->endpoint_control = &usb_dpram->ep_ctrl[num - 1].out;
|
||||||
}
|
}
|
||||||
|
|
||||||
// alloc a buffer and fill in endpoint control register
|
|
||||||
_hw_endpoint_alloc(ep, transfer_type);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -387,8 +446,8 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
|
|||||||
|
|
||||||
// Init control endpoints
|
// Init control endpoints
|
||||||
tu_memclr(hw_endpoints[0], 2 * sizeof(hw_endpoint_t));
|
tu_memclr(hw_endpoints[0], 2 * sizeof(hw_endpoint_t));
|
||||||
hw_endpoint_init(0x0, 64, TUSB_XFER_CONTROL);
|
hw_endpoint_init_and_alloc(0x0, 64, TUSB_XFER_CONTROL);
|
||||||
hw_endpoint_init(0x80, 64, TUSB_XFER_CONTROL);
|
hw_endpoint_init_and_alloc(0x80, 64, TUSB_XFER_CONTROL);
|
||||||
|
|
||||||
// Init non-control endpoints
|
// Init non-control endpoints
|
||||||
reset_non_control_endpoints();
|
reset_non_control_endpoints();
|
||||||
@@ -495,7 +554,7 @@ void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const* req
|
|||||||
|
|
||||||
bool dcd_edpt_open(__unused uint8_t rhport, tusb_desc_endpoint_t const* desc_edpt) {
|
bool dcd_edpt_open(__unused uint8_t rhport, tusb_desc_endpoint_t const* desc_edpt) {
|
||||||
assert(rhport == 0);
|
assert(rhport == 0);
|
||||||
hw_endpoint_init(desc_edpt->bEndpointAddress, tu_edpt_packet_size(desc_edpt), desc_edpt->bmAttributes.xfer);
|
hw_endpoint_init_and_alloc(desc_edpt->bEndpointAddress, tu_edpt_packet_size(desc_edpt), desc_edpt->bmAttributes.xfer);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user