GlobLib
HAL and API libraries for MCUs and hardware.
stm32f103cb_usb.c
Go to the documentation of this file.
1 /*!**************************************************************************
2  @file stm32f103cb_usb.c
3  @brief Source file for stm32f103cb USB
4  @author Stuart Ianna
5  @version 0.1
6  @date June 2018
7  @copyright GNU GPLv3
8  @warning None
9  @bug
10 
11  @details
12 
13  @par Compilers
14  - arm-none-eabi-gcc (15:4.9.3+svn231177-1) 4.9.3 20150529 (prerelease)
15 ******************************************************************************/
16 #include "stm32f103cb_usb.h"
17 
18 //Circular buffer for trasmitted data
19 #define USB_FIFO_SIZE 64
20 static uint8_t txbuffer[USB_FIFO_SIZE];
21 static uint8_t head;
22 static uint8_t tail;
23 static const uint8_t mask = USB_FIFO_SIZE-1;
24 
25 /* Buffer to be used for control requests. */
26 static uint8_t usbd_control_buffer[128];
27 
28 //usb device
29 static usbd_device *usbd_dev;
30 
31 //Received data function pointer
32 static void (*data_handler)(uint8_t byte);
33 
34 static void cdcacm_data_rx_cb(usbd_device *usbd_dev_dum, uint8_t ep);
35 
36 static const struct usb_device_descriptor dev = {
37  .bLength = USB_DT_DEVICE_SIZE,
38  .bDescriptorType = USB_DT_DEVICE,
39  .bcdUSB = 0x0200,
40  .bDeviceClass = 0x0,
41  .bDeviceSubClass = 0x0,
42  .bDeviceProtocol = 0x0,
43  .bMaxPacketSize0 = 64,
44  .idVendor = 0x0483,
45  .idProduct = 0x5740,
46  .bcdDevice = 0x0200,
47  .iManufacturer = 0,
48  .iProduct = 0,
49  .iSerialNumber = 1,
50  .bNumConfigurations = 1,
51 };
52 
53 static const struct usb_endpoint_descriptor comm_endp[] = {{
54  .bLength = USB_DT_ENDPOINT_SIZE,
55  .bDescriptorType = USB_DT_ENDPOINT,
56  .bEndpointAddress = 0x83,
57  .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
58  .wMaxPacketSize = 16,
59  .bInterval = 255,
60 }};
61 
62 static const struct usb_endpoint_descriptor data_endp[] = {{
63  .bLength = USB_DT_ENDPOINT_SIZE,
64  .bDescriptorType = USB_DT_ENDPOINT,
65  .bEndpointAddress = 0x01,
66  .bmAttributes = USB_ENDPOINT_ATTR_BULK,
67  .wMaxPacketSize = 64,
68  .bInterval = 1,
69 }, {
70  .bLength = USB_DT_ENDPOINT_SIZE,
71  .bDescriptorType = USB_DT_ENDPOINT,
72  .bEndpointAddress = 0x82,
73  .bmAttributes = USB_ENDPOINT_ATTR_BULK,
74  .wMaxPacketSize = 64,
75  .bInterval = 1,
76 }};
77 
78 static const struct {
79  struct usb_cdc_header_descriptor header;
80  struct usb_cdc_call_management_descriptor call_mgmt;
81  struct usb_cdc_acm_descriptor acm;
82  struct usb_cdc_union_descriptor cdc_union;
83 } __attribute__((packed)) cdcacm_functional_descriptors = {
84  .header = {
85  .bFunctionLength = sizeof(struct usb_cdc_header_descriptor),
86  .bDescriptorType = CS_INTERFACE,
87  .bDescriptorSubtype = USB_CDC_TYPE_HEADER,
88  .bcdCDC = 0x0110,
89  },
90  .call_mgmt = {
91  .bFunctionLength =
92  sizeof(struct usb_cdc_call_management_descriptor),
93  .bDescriptorType = CS_INTERFACE,
94  .bDescriptorSubtype = USB_CDC_TYPE_CALL_MANAGEMENT,
95  .bmCapabilities = 0,
96  .bDataInterface = 1,
97  },
98  .acm = {
99  .bFunctionLength = sizeof(struct usb_cdc_acm_descriptor),
100  .bDescriptorType = CS_INTERFACE,
101  .bDescriptorSubtype = USB_CDC_TYPE_ACM,
102  .bmCapabilities = 0,
103  },
104  .cdc_union = {
105  .bFunctionLength = sizeof(struct usb_cdc_union_descriptor),
106  .bDescriptorType = CS_INTERFACE,
107  .bDescriptorSubtype = USB_CDC_TYPE_UNION,
108  .bControlInterface = 0,
109  .bSubordinateInterface0 = 1,
110  },
111 };
112 
113 static const struct usb_interface_descriptor comm_iface[] = {{
114  .bLength = USB_DT_INTERFACE_SIZE,
115  .bDescriptorType = USB_DT_INTERFACE,
116  .bInterfaceNumber = 0,
117  .bAlternateSetting = 0,
118  .bNumEndpoints = 1,
119  .bInterfaceClass = USB_CLASS_CDC,
120  .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM,
121  .bInterfaceProtocol = USB_CDC_PROTOCOL_AT,
122  .iInterface = 0,
123 
124  .endpoint = comm_endp,
125 
126  .extra = &cdcacm_functional_descriptors,
127  .extralen = sizeof(cdcacm_functional_descriptors),
128 }};
129 
130 static const struct usb_interface_descriptor data_iface[] = {{
131  .bLength = USB_DT_INTERFACE_SIZE,
132  .bDescriptorType = USB_DT_INTERFACE,
133  .bInterfaceNumber = 1,
134  .bAlternateSetting = 0,
135  .bNumEndpoints = 2,
136  .bInterfaceClass = USB_CLASS_DATA,
137  .bInterfaceSubClass = 0,
138  .bInterfaceProtocol = 0,
139  .iInterface = 0,
140 
141  .endpoint = data_endp,
142 }};
143 
144 static const struct usb_interface ifaces[] = {{
145  .num_altsetting = 1,
146  .altsetting = comm_iface,
147 }, {
148  .num_altsetting = 1,
149  .altsetting = data_iface,
150 }};
151 
152 static const struct usb_config_descriptor config = {
153  .bLength = USB_DT_CONFIGURATION_SIZE,
154  .bDescriptorType = USB_DT_CONFIGURATION,
155  .wTotalLength = 0,
156  .bNumInterfaces = 2,
157  .bConfigurationValue = 1,
158  .iConfiguration = 0,
159  .bmAttributes = 0x80,
160  .bMaxPower = 0x32,
161 
162  .interface = ifaces,
163 };
164 
165 static const char *usb_strings[] = {
166  "asdfgh"
167 };
168 
169 
170 static int cdcacm_control_request(usbd_device *usbd_dev_dum,
171  struct usb_setup_data *req, uint8_t **buf,
172  uint16_t *len, void (**complete)(usbd_device *usbd_dev,
173  struct usb_setup_data *req)){
174 
175  (void)complete;
176  (void)buf;
177  (void)usbd_dev_dum;
178 
179  switch (req->bRequest) {
180  case USB_CDC_REQ_SET_CONTROL_LINE_STATE: {
181 
182  char local_buf[10];
183  struct usb_cdc_notification *notif = (void *)local_buf;
184 
185  /* We echo signals back to host as notification. */
186  notif->bmRequestType = 0xA1;
187  notif->bNotification = USB_CDC_NOTIFY_SERIAL_STATE;
188  notif->wValue = 0;
189  notif->wIndex = 0;
190  notif->wLength = 2;
191  local_buf[8] = req->wValue & 3;
192  local_buf[9] = 0;
193  // usbd_ep_write_packet(0x83, buf, 10);
194  return 1;
195  }
196 
197  case USB_CDC_REQ_SET_LINE_CODING:
198  if (*len < sizeof(struct usb_cdc_line_coding))
199  return 0;
200  return 1;
201  }
202  return 0;
203 }
204 
205 
206 static void cdcacm_set_config(usbd_device *usbd_dev_dum, uint16_t wValue)
207 {
208  (void)wValue;
209  (void)usbd_dev_dum;
210 
211  usbd_ep_setup(usbd_dev, 0x01, USB_ENDPOINT_ATTR_BULK, 64, cdcacm_data_rx_cb);
212  usbd_ep_setup(usbd_dev, 0x82, USB_ENDPOINT_ATTR_BULK, 64, NULL);
213  usbd_ep_setup(usbd_dev, 0x83, USB_ENDPOINT_ATTR_INTERRUPT, 16, NULL);
214 
215  usbd_register_control_callback(
216  usbd_dev,
217  USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE,
218  USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT,
219  (usbd_control_callback)cdcacm_control_request);
220 }
221 
222 //This is called when data is received
223 static void cdcacm_data_rx_cb(usbd_device *usbd_dev_dum, uint8_t ep)
224 {
225  (void)ep;
226  (void)usbd_dev_dum;
227 
228  uint8_t buffer[64];
229  static uint8_t flashPos = 0;
230  static volatile uint8_t last;
231  uint8_t length;
232 
233  length = usbd_ep_read_packet(usbd_dev, 0x01, buffer, 64);
234 
235  for(uint8_t i = 0; i < length; i++){
236 
237  //This conditional statement checks if 8 NULL characters have been
238  //sent through USB.
239  //This signals a reset to bootloader and is used to trigger a software
240  //reprogram
241  if((buffer[i] == '\0') && (last == '\0')){
242 
243  flashPos++;
244 
245  if(flashPos > 8){
246 
247  rcc_periph_clock_enable(RCC_BKP);
248  rcc_periph_clock_enable(RCC_PWR);
249  pwr_disable_backup_domain_write_protect();
250  BKP_DR1 = 1234;
251  pwr_enable_backup_domain_write_protect();
252  USB_disconnect();
253  POWER_reset();
254  }
255 
256  }
257  else{
258 
259  flashPos = 0;
260  }
261 
262  //Check f_pointer is valid
263  if(data_handler != NULL){
264 
265  data_handler(buffer[i]);
266  }
267  last = buffer[i];
268  }
269 }
270 
271 void USB_disconnect(void){
272 
273  //Disable the USB peripheral
274  *((uint32_t*)( 0x40005C40)) |= 0x03;
275 
276  //Pull both lines low to tell the host the device is disonnected
279  pinLow(PORTA,PIN11);
280  pinLow(PORTA,PIN12);
281 
282  //Delay for host to recognise change
283  for(volatile int i = 0; i < 120000;i++);
284 }
285 
286 
287 void USB_setup(void){
288 
289  USB_disconnect();
290  data_handler = NULL;
291  usbd_dev = usbd_init(&st_usbfs_v1_usb_driver,
292  &dev,
293  &config,
294  usb_strings,
295  1,
296  usbd_control_buffer,
297  sizeof(usbd_control_buffer));
298  usbd_register_set_config_callback(usbd_dev, cdcacm_set_config);
299 
300 
301  //Need to have this here to handle initial setup of USB
302  for(volatile int i = 0; i < 50000; i++){
303 
304  usbd_poll(usbd_dev);
305  }
306 
307 }
308 
309 void USB_setGet(void (*data_available)(uint8_t)){
310 
311  //Set the handler for available data
312  data_handler = data_available;
313 }
314 
315 //This has two functions
316 // 1. It handles control requests from the host
317 // 2. It sends all data waiting in the transmit buffer
318 void USB_update(void){
319 
320  uint8_t toSend[USB_FIFO_SIZE];
321  uint8_t pos = 0;
322 
323  while(head != tail){
324 
325  toSend[pos++] = txbuffer[tail];
326  tail++;
327  tail = (tail & mask);
328  }
329 
330  if(pos){
331 
332  toSend[pos] = 0;
333  usbd_ep_write_packet(usbd_dev, 0x82, toSend, pos);
334  }
335 
336  usbd_poll(usbd_dev);
337 }
338 
339 //This adds a byte to the transmit buffer
340 void USB_put(uint8_t byte){
341 
342  txbuffer[head] = byte;
343  head++;
344  head = (head & mask);
345 }
Setup the port for digital output.
void pinLow(gpio_port port, gpio_pin pin)
Set a given gpio pin on a port to logic low.
void USB_put(uint8_t byte)
Send a single byte on USB.
void USB_setGet(void(*data_available)(uint8_t))
Set the function called when data is received on the USB.
void USB_disconnect(void)
Dissconnect the USB device from the HOST.
void POWER_reset(void)
Resets the system.
void USB_setup(void)
Initialize the USB device.
mcu_error pinSetup(gpio_mode mode, gpio_port port, gpio_pin pin)
Setup a GPIO pin for a given function.
void USB_update(void)
Update the USB peripheral.
Pin 11 of the port.
Port A of the MCU.
Pin 12 of the port.
Header file for stm32f103cb USB.