Skip to content

Instantly share code, notes, and snippets.

@notro
Created February 8, 2021 15:54
Show Gist options
  • Save notro/c80b99f311162dce65e7f8819a5321d9 to your computer and use it in GitHub Desktop.
Save notro/c80b99f311162dce65e7f8819a5321d9 to your computer and use it in GitHub Desktop.
Add control loopback test
diff --git a/usb/device/dev_lowlevel/dev_lowlevel.c b/usb/device/dev_lowlevel/dev_lowlevel.c
index cf53170..6facc39 100644
--- a/usb/device/dev_lowlevel/dev_lowlevel.c
+++ b/usb/device/dev_lowlevel/dev_lowlevel.c
@@ -43,6 +43,8 @@ static volatile bool configured = false;
// Global data buffer for EP0
static uint8_t ep0_buf[64];
+// Loopback buffer for ep0
+static uint8_t ep0_test_buf[64];
// Struct defining the device configuration
static struct usb_device_configuration dev_config = {
@@ -207,7 +209,13 @@ void usb_device_init() {
// and when a setup packet is received
usb_hw->inte = USB_INTS_BUFF_STATUS_BITS |
USB_INTS_BUS_RESET_BITS |
- USB_INTS_SETUP_REQ_BITS;
+ USB_INTS_SETUP_REQ_BITS |
+ USB_INTS_STALL_BITS |
+ USB_INTS_ERROR_CRC_BITS |
+ USB_INTS_ERROR_BIT_STUFF_BITS |
+ USB_INTS_ERROR_RX_OVERFLOW_BITS |
+ USB_INTS_ERROR_RX_TIMEOUT_BITS |
+ USB_INTS_ERROR_DATA_SEQ_BITS;
// Set up endpoints (endpoint control registers)
// described by device configuration
@@ -241,7 +249,8 @@ void usb_start_transfer(struct usb_endpoint_configuration *ep, uint8_t *buf, uin
// For multi packet transfers see the tinyusb port.
assert(len <= 64);
- printf("Start transfer of len %d on ep addr 0x%x\n", len, ep->descriptor->bEndpointAddress);
+ printf("Start transfer of len %d on ep addr 0x%x pid=%u\n",
+ len, ep->descriptor->bEndpointAddress, ep->next_pid);
// Prepare buffer control register value
uint32_t val = len | USB_BUF_CTRL_AVAIL;
@@ -376,9 +385,15 @@ void usb_set_device_configuration(volatile struct usb_setup_packet *pkt) {
*/
void usb_handle_setup_packet(void) {
volatile struct usb_setup_packet *pkt = (volatile struct usb_setup_packet *) &usb_dpram->setup_packet;
- uint8_t req_direction = pkt->bmRequestType;
+ uint8_t req_recipient = pkt->bmRequestType & USB_REQ_TYPE_RECIPIENT_MASK;
+ uint8_t req_type = pkt->bmRequestType & USB_REQ_TYPE_TYPE_MASK;
+ uint8_t req_direction = pkt->bmRequestType & USB_DIR_IN;
uint8_t req = pkt->bRequest;
+ printf("%s: bRequest=0x%02x bmRequestType=0x%x %s wLength=%u\n",
+ __func__, pkt->bRequest, pkt->bmRequestType,
+ req_direction == USB_DIR_IN ? "IN" : "OUT", pkt->wLength);
+
// Reset PID to 1 for EP0 IN
usb_get_endpoint_configuration(EP0_IN_ADDR)->next_pid = 1u;
@@ -387,6 +402,14 @@ void usb_handle_setup_packet(void) {
usb_set_device_address(pkt);
} else if (req == USB_REQUEST_SET_CONFIGURATION) {
usb_set_device_configuration(pkt);
+ } else if (req_type == USB_REQ_TYPE_TYPE_VENDOR &&
+ req_recipient == USB_REQ_TYPE_RECIPIENT_INTERFACE &&
+ req == 0x01) {
+ printf("Loopback OUT request (0x%x)\r\n", pkt->bRequest);
+
+ usb_get_endpoint_configuration(EP0_OUT_ADDR)->next_pid = 1;
+
+ usb_start_transfer(usb_get_endpoint_configuration(EP0_OUT_ADDR), NULL, pkt->wLength);
} else {
printf("Other OUT request (0x%x)\r\n", pkt->bRequest);
}
@@ -413,6 +436,12 @@ void usb_handle_setup_packet(void) {
default:
printf("Unhandled GET_DESCRIPTOR type 0x%x\r\n", descriptor_type);
}
+ } else if (req_type == USB_REQ_TYPE_TYPE_VENDOR &&
+ req_recipient == USB_REQ_TYPE_RECIPIENT_INTERFACE &&
+ req == 0x02) {
+ printf("Loopback IN request (0x%x)\r\n", pkt->bRequest);
+ usb_start_transfer(usb_get_endpoint_configuration(EP0_IN_ADDR), ep0_test_buf,
+ pkt->wLength > 64 ? 64 : pkt->wLength);
} else {
printf("Other IN request (0x%x)\r\n", pkt->bRequest);
}
@@ -442,7 +471,7 @@ static void usb_handle_ep_buff_done(struct usb_endpoint_configuration *ep) {
*/
static void usb_handle_buff_done(uint ep_num, bool in) {
uint8_t ep_addr = ep_num | (in ? USB_DIR_IN : 0);
- printf("EP %d (in = %d) done\n", ep_num, in);
+ printf("EP %d (in = %d, addr=0x%x) done\n", ep_num, in, ep_addr);
for (uint i = 0; i < USB_NUM_ENDPOINTS; i++) {
struct usb_endpoint_configuration *ep = &dev_config.endpoints[i];
if (ep->descriptor && ep->handler) {
@@ -486,6 +515,39 @@ void isr_usbctrl(void) {
uint32_t status = usb_hw->ints;
uint32_t handled = 0;
+ printf("\n%s (status=0x%x) [\n", __func__, status);
+
+ if (status & USB_INTS_ERROR_DATA_SEQ_BITS) {
+ printf("DATA SEQ error (wrong PID)\n");
+ handled |= USB_INTS_ERROR_DATA_SEQ_BITS;
+ usb_hw_clear->sie_status = USB_SIE_STATUS_DATA_SEQ_ERROR_BITS;
+ }
+ if (status & USB_INTS_STALL_BITS) {
+ printf("STALL error\n");
+ handled |= USB_INTS_STALL_BITS;
+ usb_hw_clear->sie_status = USB_SIE_STATUS_STALL_REC_BITS;
+ }
+ if (status & USB_INTS_ERROR_RX_TIMEOUT_BITS) {
+ printf("RX TIMEOUT error\n");
+ handled |= USB_INTS_ERROR_RX_TIMEOUT_BITS;
+ usb_hw_clear->sie_status = USB_SIE_STATUS_RX_TIMEOUT_BITS;
+ }
+ if (status & USB_INTS_ERROR_RX_OVERFLOW_BITS) {
+ printf("RX OVERFLOW error\n");
+ handled |= USB_INTS_ERROR_RX_OVERFLOW_BITS;
+ usb_hw_clear->sie_status = USB_SIE_STATUS_RX_OVERFLOW_BITS;
+ }
+ if (status & USB_INTS_ERROR_BIT_STUFF_BITS) {
+ printf("BIT STUFF error\n");
+ handled |= USB_INTS_ERROR_BIT_STUFF_BITS;
+ usb_hw_clear->sie_status = USB_SIE_STATUS_BIT_STUFF_ERROR_BITS;
+ }
+ if (status & USB_INTS_ERROR_CRC_BITS) {
+ printf("CRC error\n");
+ handled |= USB_INTS_ERROR_CRC_BITS;
+ usb_hw_clear->sie_status = USB_SIE_STATUS_CRC_ERROR_BITS;
+ }
+
// Setup packet received
if (status & USB_INTS_SETUP_REQ_BITS) {
handled |= USB_INTS_SETUP_REQ_BITS;
@@ -511,6 +573,8 @@ void isr_usbctrl(void) {
if (status ^ handled) {
panic("Unhandled IRQ 0x%x\n", (uint) (status ^ handled));
}
+
+ printf("]\n");
}
/**
@@ -521,6 +585,7 @@ void isr_usbctrl(void) {
* @param len the length that was sent
*/
void ep0_in_handler(uint8_t *buf, uint16_t len) {
+ printf("%s: len=%u\n", __func__, len);
if (should_set_address) {
// Set actual device address in hardware
usb_hw->dev_addr_ctrl = dev_addr;
@@ -528,12 +593,18 @@ void ep0_in_handler(uint8_t *buf, uint16_t len) {
} else {
// Receive a zero length status packet from the host on EP0 OUT
struct usb_endpoint_configuration *ep = usb_get_endpoint_configuration(EP0_OUT_ADDR);
+ ep->next_pid = 1;
usb_start_transfer(ep, NULL, 0);
}
}
void ep0_out_handler(uint8_t *buf, uint16_t len) {
- ;
+ printf("%s: len=%u\n", __func__, len);
+ if (len) {
+ memcpy(ep0_test_buf, buf, len > 64 ? 64 : len);
+ struct usb_endpoint_configuration *ep = usb_get_endpoint_configuration(EP0_IN_ADDR);
+ usb_start_transfer(ep, NULL, 0);
+ }
}
// Device specific functions
diff --git a/usb/device/dev_lowlevel/dev_lowlevel_loopback.py b/usb/device/dev_lowlevel/dev_lowlevel_loopback.py
old mode 100755
new mode 100644
index 82bf478..9c7c7ac
--- a/usb/device/dev_lowlevel/dev_lowlevel_loopback.py
+++ b/usb/device/dev_lowlevel/dev_lowlevel_loopback.py
@@ -45,4 +45,18 @@ test_string = "Hello World!"
outep.write(test_string)
from_device = inep.read(len(test_string))
-print("Device Says: {}".format(''.join([chr(x) for x in from_device])))
+print("Bulk Endpoint Says: {}".format(''.join([chr(x) for x in from_device])))
+
+typ_vendor_int_in = usb.util.build_request_type(
+ usb.util.CTRL_IN,
+ usb.util.CTRL_TYPE_VENDOR,
+ usb.util.CTRL_RECIPIENT_INTERFACE)
+typ_vendor_int_out = usb.util.build_request_type(
+ usb.util.CTRL_OUT,
+ usb.util.CTRL_TYPE_VENDOR,
+ usb.util.CTRL_RECIPIENT_INTERFACE)
+
+dev.ctrl_transfer(typ_vendor_int_out, 0x01, 0, 0, test_string)
+from_device = dev.ctrl_transfer(typ_vendor_int_in, 0x02, 0, 0, len(test_string))
+
+print("Control Endpoint Says: {}".format(''.join([chr(x) for x in from_device])))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment