~ruther/stm32h747i-disco-usb-image-viewer

8fd37eafa2cd7ba0dc587922c113260ce53aabca — Rutherther 5 months ago a9ffd72
feat: move all sending instructions to generic send functions
4 files changed, 136 insertions(+), 90 deletions(-)

M include/usb.h
M include/usb_device.h
M src/usb.c
M src/usb_device.c
M include/usb.h => include/usb.h +44 -13
@@ 1,8 1,16 @@
#include <stdint.h>
#include <stm32h747xx.h>

#ifndef USB_H
#define USB_H

// NOTE: fields here have to be kept in same order,
// and care must be taken the structs are not padded.
// They are from the usb standard.

#define USB_SUBLANG_ENGLISH_US 0x01
#define USB_LANG_ENGLISH 0x09

#pragma GCC diagnostic error "-Wpadded"
typedef struct {
  uint8_t self_powered : 1;


@@ 127,7 135,7 @@ typedef struct {
  uint8_t reserved1 : 1;
  uint8_t self_powered : 1;
  uint8_t remote_wakeup : 1;
  uint8_t reserved2: 5;
  uint8_t reserved_zeros: 5;
} usb_configuration_descriptor_attributes;

typedef struct __attribute__((packed)) {


@@ 160,10 168,10 @@ typedef enum {
  USB_ENDPOINT_IN = 1,
} usb_endpoint_direction_t;

typedef struct {
typedef struct __attribute__((packed)) {
  uint8_t endpoint_number : 4;
  uint8_t reserved : 3;
  uint8_t direction : 1;
  usb_endpoint_direction_t direction : 1;
} usb_endpoint_address_t;

typedef enum {


@@ 215,28 223,51 @@ typedef struct {
  uint8_t *bString;
} usb_unicode_string_descriptor_t;

void usb_generic_send(uint8_t *data, uint16_t size,
// NOTE: End of structs from usb specification here

typedef struct __attribute__((packed)) {
  usb_device_descriptor_t device_descriptor;
  usb_device_qualifier_t device_qualifier;
  // NOTE: keep these three fields in this order!
  usb_configuration_descriptor_t configuration_descriptor;
  usb_interface_descriptor_t interface_descriptor;
  usb_endpoint_descriptor_t endpoint_descriptors[8];
  //
  usb_string_descriptor_zero_t string_descriptor_zero;
  usb_unicode_string_descriptor_t *string_descriptors;
} usb_class_t;

void usb_generic_send(USB_OTG_INEndpointTypeDef *endpoint,
                      uint8_t *data,
                      uint16_t size,
                      volatile uint32_t *fifo_tx_target);
void usb_generic_read(uint8_t *data, uint16_t size,
void usb_generic_read(uint8_t *data,
                      uint16_t size,
                      volatile uint32_t *fifo_rx_source);
void usb_send_descriptor(usb_descriptor_t *descriptor,
void usb_send_descriptor(USB_OTG_INEndpointTypeDef *endpoint,
                         usb_descriptor_t *descriptor,
                         volatile uint32_t *fifo_tx_target);
void usb_send_device_descriptor(usb_device_descriptor_t *descriptor,
void usb_send_device_descriptor(USB_OTG_INEndpointTypeDef *endpoint,
                                usb_device_descriptor_t *descriptor,
                                volatile uint32_t *fifo_tx_target);
void usb_send_device_qualifier_descriptor(usb_device_qualifier_t *descriptor,
void usb_send_device_qualifier_descriptor(USB_OTG_INEndpointTypeDef* endpoint,usb_device_qualifier_t *descriptor,
                                          volatile uint32_t *fifo_tx_target);
/* void usb_send_ack(uint32_t* fifo_tx_target); */
void usb_send_configuration_descriptor(
    usb_configuration_descriptor_t *descriptor,
    volatile uint32_t *fifo_tx_target);
void usb_send_interface_descriptor(usb_interface_descriptor_t *descriptor,
void usb_send_configuration_descriptor(USB_OTG_INEndpointTypeDef* endpoint,
                                       usb_class_t *class,
                                       volatile uint32_t *fifo_tx_target);
void usb_send_interface_descriptor(USB_OTG_INEndpointTypeDef *endpoint,
                                   usb_interface_descriptor_t *descriptor,
                                   volatile uint32_t *fifo_tx_target);
void usb_send_endpoint_descriptor(usb_endpoint_descriptor_t *descriptor,
void usb_send_endpoint_descriptor(USB_OTG_INEndpointTypeDef *endpoint,
                                  usb_endpoint_descriptor_t *descriptor,
                                  volatile uint32_t *fifo_tx_target);
void usb_send_string_descriptor_zero(
    USB_OTG_INEndpointTypeDef *endpoint,
    usb_string_descriptor_zero_t *string_descriptor,
    volatile uint32_t *fifo_tx_target);
void usb_send_unicode_string_descriptor(
    USB_OTG_INEndpointTypeDef *endpoint,
    usb_unicode_string_descriptor_t *string_descriptor,
    volatile uint32_t *fifo_tx_target);


M include/usb_device.h => include/usb_device.h +0 -8
@@ 24,14 24,6 @@ typedef struct {
} usb_fifo_t;

typedef struct {
  usb_device_descriptor_t device_descriptor;
  usb_configuration_descriptor_t configuration_descriptor;
  usb_interface_descriptor_t interface_descriptor;
  usb_device_qualifier_t device_qualifier;
  usb_endpoint_descriptor_t endpoint_descriptors[8];
} usb_class_t;

typedef struct {
  USB_OTG_GlobalTypeDef *core;
  USB_OTG_DeviceTypeDef *device;


M src/usb.c => src/usb.c +64 -20
@@ 1,4 1,6 @@
#include "usb.h"
#include "usb_device.h"
#include <stm32h747xx.h>

typedef union {
  uint32_t word;


@@ 6,7 8,20 @@ typedef union {
  uint8_t bytes[4];
} usb_data_t;

void usb_generic_send(uint8_t* data, uint16_t size, volatile uint32_t *fifo_tx_target) {
void usb_generic_send(USB_OTG_INEndpointTypeDef *endpoint,
                      uint8_t *data,
                      uint16_t size,
                      volatile uint32_t *fifo_tx_target) {
  if (endpoint->DIEPCTL & USB_OTG_DIEPCTL_EPENA) {
    // this is bad! Can't send the packet, this shouldn't get here, ever.
    while (endpoint->DIEPCTL & USB_OTG_DIEPCTL_EPENA);
  }

  // TODO: generic max packet size
  uint16_t packet_count = size + 63 / 64;

  endpoint->DIEPTSIZ = (packet_count << USB_OTG_DIEPTSIZ_PKTCNT_Pos) | (size << USB_OTG_DIEPTSIZ_XFRSIZ_Pos);

  usb_data_t tx_data;
  uint8_t subWordBytes = size % 4;
  uint8_t wordCount = size / 4;


@@ 25,6 40,8 @@ void usb_generic_send(uint8_t* data, uint16_t size, volatile uint32_t *fifo_tx_t
    }
    *fifo_tx_target = tx_data.word;
  }

  endpoint->DIEPCTL |= USB_OTG_DIEPCTL_CNAK | USB_OTG_DIEPCTL_EPENA;
}

void usb_generic_read(uint8_t *data, uint16_t size, volatile uint32_t *fifo_rx_source) {


@@ 47,43 64,66 @@ void usb_generic_read(uint8_t *data, uint16_t size, volatile uint32_t *fifo_rx_s
  }
}

void usb_send_descriptor(usb_descriptor_t *descriptor,
void usb_send_descriptor(USB_OTG_INEndpointTypeDef *endpoint,
                         usb_descriptor_t *descriptor,
                         volatile uint32_t *fifo_tx_target) {
  usb_generic_send((uint8_t*)descriptor, descriptor->bLength, fifo_tx_target);
  usb_generic_send(endpoint, (uint8_t*)descriptor, descriptor->bLength, fifo_tx_target);
}

void usb_send_configuration_descriptor(
    usb_configuration_descriptor_t *descriptor, volatile uint32_t *fifo_tx_target) {
  descriptor->header.bDescriptorType = DESCRIPTOR_CONFIGURATION;
  descriptor->header.bLength = sizeof(usb_configuration_descriptor_t);
  usb_send_descriptor(&descriptor->header, fifo_tx_target);
void usb_send_configuration_descriptor(USB_OTG_INEndpointTypeDef* endpoint,
                                       usb_class_t *class,
                                       volatile uint32_t *fifo_tx_target) {
  class->configuration_descriptor.header.bDescriptorType = DESCRIPTOR_CONFIGURATION;
  class->configuration_descriptor.header.bLength = sizeof(usb_configuration_descriptor_t);
  class->interface_descriptor.header.bDescriptorType = DESCRIPTOR_INTERFACE;
  class->interface_descriptor.header.bLength = sizeof(usb_interface_descriptor_t);
  uint16_t total_length =
    sizeof(usb_configuration_descriptor_t) +
    sizeof(usb_interface_descriptor_t) +
    class->interface_descriptor.bNumEndpoints * sizeof(usb_endpoint_descriptor_t);

  for (int i = 0; i < class->interface_descriptor.bNumEndpoints; i++) {
    class->endpoint_descriptors[i].header.bDescriptorType = DESCRIPTOR_ENDPOINT;
    class->endpoint_descriptors[i].header.bLength = sizeof(usb_endpoint_descriptor_t);
  }

  // NOTE: since the memory layout is: configuration, interface, endpoints,
  // we can send directly like this.
  usb_generic_send(endpoint,
                   (uint8_t*)&class->configuration_descriptor,
                   total_length, fifo_tx_target);
}
void usb_send_device_descriptor(usb_device_descriptor_t *descriptor,
                                   volatile uint32_t *fifo_tx_target) {
void usb_send_device_descriptor(USB_OTG_INEndpointTypeDef *endpoint,
                                usb_device_descriptor_t *descriptor,
                                volatile uint32_t *fifo_tx_target) {
  descriptor->header.bDescriptorType = DESCRIPTOR_DEVICE;
  descriptor->header.bLength = sizeof(usb_device_descriptor_t);
  usb_send_descriptor(&descriptor->header, fifo_tx_target);
  usb_send_descriptor(endpoint, &descriptor->header, fifo_tx_target);
}
void usb_send_device_qualifier_descriptor(usb_device_qualifier_t *descriptor,
void usb_send_device_qualifier_descriptor(USB_OTG_INEndpointTypeDef *endpoint,
                                          usb_device_qualifier_t *descriptor,
                                   volatile uint32_t *fifo_tx_target) {
  descriptor->header.bDescriptorType = DESCRIPTOR_DEVICE_QUALIFIER;
  descriptor->header.bLength = sizeof(usb_device_qualifier_t);
  usb_send_descriptor(&descriptor->header, fifo_tx_target);
  usb_send_descriptor(endpoint, &descriptor->header, fifo_tx_target);
}
void usb_send_interface_descriptor(usb_interface_descriptor_t *descriptor,
void usb_send_interface_descriptor(USB_OTG_INEndpointTypeDef *endpoint,
                                   usb_interface_descriptor_t *descriptor,
                                   volatile uint32_t *fifo_tx_target) {
  descriptor->header.bDescriptorType = DESCRIPTOR_INTERFACE;
  descriptor->header.bLength = sizeof(usb_interface_descriptor_t);
  usb_send_descriptor(&descriptor->header, fifo_tx_target);
  usb_send_descriptor(endpoint, &descriptor->header, fifo_tx_target);
}
void usb_send_endpoint_descriptor(usb_endpoint_descriptor_t *descriptor,
void usb_send_endpoint_descriptor(USB_OTG_INEndpointTypeDef *endpoint,
                                  usb_endpoint_descriptor_t *descriptor,
                                  volatile uint32_t *fifo_tx_target) {
  descriptor->header.bDescriptorType = DESCRIPTOR_ENDPOINT;
  descriptor->header.bLength = sizeof(usb_endpoint_descriptor_t);
  usb_send_descriptor(&descriptor->header, fifo_tx_target);
  usb_send_descriptor(endpoint, &descriptor->header, fifo_tx_target);
}

void usb_send_string_descriptor_zero(usb_string_descriptor_zero_t *string_descriptor,
void usb_send_string_descriptor_zero(USB_OTG_INEndpointTypeDef *endpoint,
                                     usb_string_descriptor_zero_t *string_descriptor,
                              volatile uint32_t *fifo_tx_target) {
  usb_data_t data;
  data.word = 0;


@@ 102,12 142,14 @@ void usb_send_string_descriptor_zero(usb_string_descriptor_zero_t *string_descri

  // TODO: Now the rest only from wLANGID[1..]
  if (string_descriptor->header.bLength > 4) {
    usb_generic_send((uint8_t *)&string_descriptor->wLANGID[1],
    usb_generic_send(endpoint,
                     (uint8_t *)&string_descriptor->wLANGID[1],
                     string_descriptor->header.bLength - 4,
                     fifo_tx_target);
  }
}
void usb_send_unicode_string_descriptor(
    USB_OTG_INEndpointTypeDef *endpoint,
    usb_unicode_string_descriptor_t *string_descriptor,
    volatile uint32_t *fifo_tx_target) {
  usb_data_t data = { .word = 0 };


@@ 121,6 163,8 @@ void usb_send_unicode_string_descriptor(
  *fifo_tx_target = data.word;

  if (string_descriptor->header.bLength > 4) {
    usb_generic_send(&string_descriptor->bString[2], string_descriptor->header.bLength - 4, fifo_tx_target);
    usb_generic_send(endpoint, &string_descriptor->bString[2],
                     string_descriptor->header.bLength - 4,
                     fifo_tx_target);
  }
}

M src/usb_device.c => src/usb_device.c +28 -49
@@ 142,28 142,6 @@ typedef struct {
  uint8_t endpoint_num;
} packet_info_t;

void usb_prepare_send_packet(USB_OTG_INEndpointTypeDef* in, uint8_t packet_count, uint8_t packet_size) {
  if (ep enabled) {
    // this is bad! Can't send the packet
  }

  in->DIEPTSIZ = (packet_count << USB_OTG_DIEPTSIZ_PKTCNT_Pos) | (packet_size << USB_OTG_DIEPTSIZ_XFRSIZ_Pos);
}

void usb_control_send(usb_device_t *device, uint8_t value) {
    usb_prepare_send_packet(&device->in[0],
                            1, sizeof(uint8_t));
    usb_generic_send(&value,
                     sizeof(uint8_t), &device->fifos[0].data[0]);
    device->in[0].DIEPCTL |= USB_OTG_DIEPCTL_CNAK | USB_OTG_DIEPCTL_EPENA;
}

void usb_control_send_ack(usb_device_t* device) {
    usb_prepare_send_packet(&device->in[0],
                            1, sizeof(uint8_t));
    device->in[0].DIEPCTL |= USB_OTG_DIEPCTL_CNAK | USB_OTG_DIEPCTL_EPENA;
}

void usb_handle_setup(usb_device_t *device, usb_setup_command_t* cmd) {
  switch (cmd->bRequest) {
  case USB_SETUP_GET_STATUS: {


@@ 197,10 175,8 @@ void usb_handle_setup(usb_device_t *device, usb_setup_command_t* cmd) {
      break;
    }

    usb_prepare_send_packet(device, 1, size);
    usb_generic_send(packet, size,
    usb_generic_send(device->in, packet, size,
                     &device->fifos[0].data[0]);
    device->in[0].DIEPCTL |= USB_OTG_DIEPCTL_CNAK | USB_OTG_DIEPCTL_EPENA;
  }
    break;
  case USB_SETUP_GET_DESCRIPTOR: {


@@ 209,30 185,30 @@ void usb_handle_setup(usb_device_t *device, usb_setup_command_t* cmd) {

    switch (descriptor_type) {
    case DESCRIPTOR_DEVICE:
      usb_prepare_send_packet(&device->in[0],
                              1, sizeof(usb_device_descriptor_t));
      usb_send_device_descriptor(&device->class.device_descriptor, &device->fifos[0].data[0]);
      device->in[0].DIEPCTL |= USB_OTG_DIEPCTL_CNAK | USB_OTG_DIEPCTL_EPENA;
      usb_send_device_descriptor(device->in, &device->class.device_descriptor, &device->fifos[0].data[0]);
      break;
    case DESCRIPTOR_CONFIGURATION:
      usb_prepare_send_packet(&device->in[0],
                              1, sizeof(usb_configuration_descriptor_t));
      usb_send_configuration_descriptor(&device->class.configuration_descriptor, &device->fifos[0].data[0]);
      device->in[0].DIEPCTL |= USB_OTG_DIEPCTL_CNAK | USB_OTG_DIEPCTL_EPENA;
      usb_send_configuration_descriptor(device->in, &device->class.configuration_descriptor, &device->fifos[0].data[0]);
      break;
    case DESCRIPTOR_STRING:
    case DESCRIPTOR_STRING: {
      if (descriptor_index == 0) {
        usb_send_string_descriptor_zero(device->in, &device->class.string_descriptor_zero, &device->fifos[0].data[0]);
      } else {
        uint8_t index = descriptor_index - 1;
        // NOTE: the user could potentially read different memory part!!
        // This has to be fixed, the length has to be stored somewhere.
        usb_send_unicode_string_descriptor(device->in, &device->class.string_descriptors[index], &device->fifos[0].data[0]);
      }
    }
      break;
    case DESCRIPTOR_INTERFACE:
      usb_send_interface_descriptor(device->in, &device->class.interface_descriptor, &device->fifos[0].data[0]);
      break;
    case DESCRIPTOR_ENDPOINT:
      usb_prepare_send_packet(&device->in[0],
                              1, sizeof(usb_endpoint_descriptor_t));
      usb_send_endpoint_descriptor(&device->class.endpoint_descriptors[descriptor_index], &device->fifos[0].data[0]);
      device->in[0].DIEPCTL |= USB_OTG_DIEPCTL_CNAK | USB_OTG_DIEPCTL_EPENA;
      usb_send_endpoint_descriptor(device->in, &device->class.endpoint_descriptors[descriptor_index], &device->fifos[0].data[0]);
      break;
    case DESCRIPTOR_DEVICE_QUALIFIER:
      usb_prepare_send_packet(&device->in[0],
                              1, sizeof(usb_device_qualifier_t));
      usb_send_device_qualifier_descriptor(&device->class.device_qualifier, &device->fifos[0].data[0]);
      device->in[0].DIEPCTL |= USB_OTG_DIEPCTL_CNAK | USB_OTG_DIEPCTL_EPENA;
      usb_send_device_qualifier_descriptor(device->in, &device->class.device_qualifier, &device->fifos[0].data[0]);
      break;
    case DESCRIPTOR_OTHER_SPEED_CONFIGURATION:
    case DESCRIPTOR_INTERFACE_POWER:


@@ 247,11 223,14 @@ void usb_handle_setup(usb_device_t *device, usb_setup_command_t* cmd) {
    if (device->state != ENUMERATED) {
      value = 0;
    }
    usb_control_send(device, value);
    usb_generic_send(device->in, &value, sizeof(value), &device->fifos[0].data[0]);
  }
    break;
  case USB_SETUP_GET_INTERFACE: {
    usb_control_send(device, device->class.interface_descriptor.bAlternateSetting);
    usb_generic_send(device->in,
                     &device->class.interface_descriptor.bAlternateSetting,
                     sizeof(uint8_t),
                     &device->fifos[0].data[0]);
  }
    break;
  case USB_SETUP_SET_ADDRESS:


@@ 259,18 238,18 @@ void usb_handle_setup(usb_device_t *device, usb_setup_command_t* cmd) {
                       cmd->wValue,
                       USB_OTG_DCFG_DAD_Pos,
                       0x7F);
    usb_control_send_ack(device);
    usb_generic_send(device->in, NULL, 0, &device->fifos[0].data[0]);
    device->state = SET_ADDRESS_RCVD;
    break;
  case USB_SETUP_SET_CONFIGURATION: {
    if (cmd->wValue == 0) {
      device->state = SET_ADDRESS_RCVD;
      usb_control_send_ack(device);
      usb_generic_send(device->in, NULL, 0, &device->fifos[0].data[0]);

      // TODO disable endpoints
    } else if (cmd->wValue == device->class.configuration_descriptor.bConfigurationValue) {
      device->state = ENUMERATED;
      usb_control_send_ack(device);
      usb_generic_send(device->in, NULL, 0, &device->fifos[0].data[0]);

      // TODO setup endpoints
    } else {


@@ 292,7 271,7 @@ void usb_handle_setup(usb_device_t *device, usb_setup_command_t* cmd) {
      break;
    }

    usb_control_send_ack(device);
    usb_generic_send(device->in, NULL, 0, &device->fifos[0].data[0]);
    break;
  case USB_SETUP_SET_FEATURE:
    switch (cmd->wValue) {


@@ 308,7 287,7 @@ void usb_handle_setup(usb_device_t *device, usb_setup_command_t* cmd) {
      break;
    }

    usb_control_send_ack(device);
    usb_generic_send(device->in, NULL, 0, &device->fifos[0].data[0]);
    break;
  case USB_SETUP_SET_DESCRIPTOR:
  case USB_SETUP_SET_INTERFACE:

Do not follow this link