Browse Source

Add L052/dfu bootloader.

flabbergast 1 year ago
parent
commit
6f1916fc2a
7 changed files with 916 additions and 218 deletions
  1. 3
    0
      README.md
  2. 220
    218
      usb_cdcacm/cdcacm.c
  3. 29
    0
      usb_dfu/Makefile
  4. 41
    0
      usb_dfu/README.md
  5. 89
    0
      usb_dfu/hardfault.c
  6. 101
    0
      usb_dfu/lib-flash-from-ram.patch
  7. 433
    0
      usb_dfu/usbdfu.c

+ 3
- 0
README.md View File

@@ -10,6 +10,9 @@ They aren't too specific for the bat boards, except the usual pinout considerati
10 10
 
11 11
 The board presents itself as a serial port (CDC). It echoes back what it receives; toggling the LED after each received packet. Pressing the `PA1` button will print `hello, world` over this port.
12 12
 
13
+### usb_dfu
14
+
15
+L052 only. This is the DFU bootloader that I use on the bat boards with L052. More info about it on [the bat board] main page.
13 16
 
14 17
 ## General setup notes
15 18
 

+ 220
- 218
usb_cdcacm/cdcacm.c View File

@@ -27,20 +27,20 @@
27 27
 #include <libopencm3/usb/cdc.h>
28 28
 
29 29
 static const struct usb_device_descriptor dev = {
30
-    .bLength = USB_DT_DEVICE_SIZE,
31
-    .bDescriptorType = USB_DT_DEVICE,
32
-    .bcdUSB = 0x0200,
33
-    .bDeviceClass = USB_CLASS_CDC,
34
-    .bDeviceSubClass = 0,
35
-    .bDeviceProtocol = 0,
36
-    .bMaxPacketSize0 = 64,
37
-    .idVendor = 0x0483,
38
-    .idProduct = 0x5740,
39
-    .bcdDevice = 0x0200,
40
-    .iManufacturer = 1,
41
-    .iProduct = 2,
42
-    .iSerialNumber = 3,
43
-    .bNumConfigurations = 1,
30
+	.bLength = USB_DT_DEVICE_SIZE,
31
+	.bDescriptorType = USB_DT_DEVICE,
32
+	.bcdUSB = 0x0200,
33
+	.bDeviceClass = USB_CLASS_CDC,
34
+	.bDeviceSubClass = 0,
35
+	.bDeviceProtocol = 0,
36
+	.bMaxPacketSize0 = 64,
37
+	.idVendor = 0x0483,
38
+	.idProduct = 0x5740,
39
+	.bcdDevice = 0x0200,
40
+	.iManufacturer = 1,
41
+	.iProduct = 2,
42
+	.iSerialNumber = 3,
43
+	.bNumConfigurations = 1,
44 44
 };
45 45
 
46 46
 /*
@@ -49,121 +49,121 @@ static const struct usb_device_descriptor dev = {
49 49
  * cdc_acm driver.
50 50
  */
51 51
 static const struct usb_endpoint_descriptor comm_endp[] = {{
52
-    .bLength = USB_DT_ENDPOINT_SIZE,
53
-    .bDescriptorType = USB_DT_ENDPOINT,
54
-    .bEndpointAddress = 0x83,
55
-    .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
56
-    .wMaxPacketSize = 16,
57
-    .bInterval = 255,
52
+	.bLength = USB_DT_ENDPOINT_SIZE,
53
+	.bDescriptorType = USB_DT_ENDPOINT,
54
+	.bEndpointAddress = 0x83,
55
+	.bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
56
+	.wMaxPacketSize = 16,
57
+	.bInterval = 255,
58 58
 }};
59 59
 
60 60
 static const struct usb_endpoint_descriptor data_endp[] = {{
61
-    .bLength = USB_DT_ENDPOINT_SIZE,
62
-    .bDescriptorType = USB_DT_ENDPOINT,
63
-    .bEndpointAddress = 0x01,
64
-    .bmAttributes = USB_ENDPOINT_ATTR_BULK,
65
-    .wMaxPacketSize = 64,
66
-    .bInterval = 1,
61
+	.bLength = USB_DT_ENDPOINT_SIZE,
62
+	.bDescriptorType = USB_DT_ENDPOINT,
63
+	.bEndpointAddress = 0x01,
64
+	.bmAttributes = USB_ENDPOINT_ATTR_BULK,
65
+	.wMaxPacketSize = 64,
66
+	.bInterval = 1,
67 67
 }, {
68
-    .bLength = USB_DT_ENDPOINT_SIZE,
69
-    .bDescriptorType = USB_DT_ENDPOINT,
70
-    .bEndpointAddress = 0x82,
71
-    .bmAttributes = USB_ENDPOINT_ATTR_BULK,
72
-    .wMaxPacketSize = 64,
73
-    .bInterval = 1,
68
+	.bLength = USB_DT_ENDPOINT_SIZE,
69
+	.bDescriptorType = USB_DT_ENDPOINT,
70
+	.bEndpointAddress = 0x82,
71
+	.bmAttributes = USB_ENDPOINT_ATTR_BULK,
72
+	.wMaxPacketSize = 64,
73
+	.bInterval = 1,
74 74
 }};
75 75
 
76 76
 static const struct {
77
-    struct usb_cdc_header_descriptor header;
78
-    struct usb_cdc_call_management_descriptor call_mgmt;
79
-    struct usb_cdc_acm_descriptor acm;
80
-    struct usb_cdc_union_descriptor cdc_union;
77
+	struct usb_cdc_header_descriptor header;
78
+	struct usb_cdc_call_management_descriptor call_mgmt;
79
+	struct usb_cdc_acm_descriptor acm;
80
+	struct usb_cdc_union_descriptor cdc_union;
81 81
 } __attribute__((packed)) cdcacm_functional_descriptors = {
82
-    .header = {
83
-        .bFunctionLength = sizeof(struct usb_cdc_header_descriptor),
84
-        .bDescriptorType = CS_INTERFACE,
85
-        .bDescriptorSubtype = USB_CDC_TYPE_HEADER,
86
-        .bcdCDC = 0x0110,
87
-    },
88
-    .call_mgmt = {
89
-        .bFunctionLength =
90
-            sizeof(struct usb_cdc_call_management_descriptor),
91
-        .bDescriptorType = CS_INTERFACE,
92
-        .bDescriptorSubtype = USB_CDC_TYPE_CALL_MANAGEMENT,
93
-        .bmCapabilities = 0,
94
-        .bDataInterface = 1,
95
-    },
96
-    .acm = {
97
-        .bFunctionLength = sizeof(struct usb_cdc_acm_descriptor),
98
-        .bDescriptorType = CS_INTERFACE,
99
-        .bDescriptorSubtype = USB_CDC_TYPE_ACM,
100
-        .bmCapabilities = 0,
101
-    },
102
-    .cdc_union = {
103
-        .bFunctionLength = sizeof(struct usb_cdc_union_descriptor),
104
-        .bDescriptorType = CS_INTERFACE,
105
-        .bDescriptorSubtype = USB_CDC_TYPE_UNION,
106
-        .bControlInterface = 0,
107
-        .bSubordinateInterface0 = 1,
108
-     }
82
+	.header = {
83
+		.bFunctionLength = sizeof(struct usb_cdc_header_descriptor),
84
+		.bDescriptorType = CS_INTERFACE,
85
+		.bDescriptorSubtype = USB_CDC_TYPE_HEADER,
86
+		.bcdCDC = 0x0110,
87
+	},
88
+	.call_mgmt = {
89
+		.bFunctionLength =
90
+			sizeof(struct usb_cdc_call_management_descriptor),
91
+		.bDescriptorType = CS_INTERFACE,
92
+		.bDescriptorSubtype = USB_CDC_TYPE_CALL_MANAGEMENT,
93
+		.bmCapabilities = 0,
94
+		.bDataInterface = 1,
95
+	},
96
+	.acm = {
97
+		.bFunctionLength = sizeof(struct usb_cdc_acm_descriptor),
98
+		.bDescriptorType = CS_INTERFACE,
99
+		.bDescriptorSubtype = USB_CDC_TYPE_ACM,
100
+		.bmCapabilities = 0,
101
+	},
102
+	.cdc_union = {
103
+		.bFunctionLength = sizeof(struct usb_cdc_union_descriptor),
104
+		.bDescriptorType = CS_INTERFACE,
105
+		.bDescriptorSubtype = USB_CDC_TYPE_UNION,
106
+		.bControlInterface = 0,
107
+		.bSubordinateInterface0 = 1,
108
+	 }
109 109
 };
110 110
 
111 111
 static const struct usb_interface_descriptor comm_iface[] = {{
112
-    .bLength = USB_DT_INTERFACE_SIZE,
113
-    .bDescriptorType = USB_DT_INTERFACE,
114
-    .bInterfaceNumber = 0,
115
-    .bAlternateSetting = 0,
116
-    .bNumEndpoints = 1,
117
-    .bInterfaceClass = USB_CLASS_CDC,
118
-    .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM,
119
-    .bInterfaceProtocol = USB_CDC_PROTOCOL_AT,
120
-    .iInterface = 0,
121
-
122
-    .endpoint = comm_endp,
123
-
124
-    .extra = &cdcacm_functional_descriptors,
125
-    .extralen = sizeof(cdcacm_functional_descriptors)
112
+	.bLength = USB_DT_INTERFACE_SIZE,
113
+	.bDescriptorType = USB_DT_INTERFACE,
114
+	.bInterfaceNumber = 0,
115
+	.bAlternateSetting = 0,
116
+	.bNumEndpoints = 1,
117
+	.bInterfaceClass = USB_CLASS_CDC,
118
+	.bInterfaceSubClass = USB_CDC_SUBCLASS_ACM,
119
+	.bInterfaceProtocol = USB_CDC_PROTOCOL_AT,
120
+	.iInterface = 0,
121
+
122
+	.endpoint = comm_endp,
123
+
124
+	.extra = &cdcacm_functional_descriptors,
125
+	.extralen = sizeof(cdcacm_functional_descriptors)
126 126
 }};
127 127
 
128 128
 static const struct usb_interface_descriptor data_iface[] = {{
129
-    .bLength = USB_DT_INTERFACE_SIZE,
130
-    .bDescriptorType = USB_DT_INTERFACE,
131
-    .bInterfaceNumber = 1,
132
-    .bAlternateSetting = 0,
133
-    .bNumEndpoints = 2,
134
-    .bInterfaceClass = USB_CLASS_DATA,
135
-    .bInterfaceSubClass = 0,
136
-    .bInterfaceProtocol = 0,
137
-    .iInterface = 0,
138
-
139
-    .endpoint = data_endp,
129
+	.bLength = USB_DT_INTERFACE_SIZE,
130
+	.bDescriptorType = USB_DT_INTERFACE,
131
+	.bInterfaceNumber = 1,
132
+	.bAlternateSetting = 0,
133
+	.bNumEndpoints = 2,
134
+	.bInterfaceClass = USB_CLASS_DATA,
135
+	.bInterfaceSubClass = 0,
136
+	.bInterfaceProtocol = 0,
137
+	.iInterface = 0,
138
+
139
+	.endpoint = data_endp,
140 140
 }};
141 141
 
142 142
 static const struct usb_interface ifaces[] = {{
143
-    .num_altsetting = 1,
144
-    .altsetting = comm_iface,
143
+	.num_altsetting = 1,
144
+	.altsetting = comm_iface,
145 145
 }, {
146
-    .num_altsetting = 1,
147
-    .altsetting = data_iface,
146
+	.num_altsetting = 1,
147
+	.altsetting = data_iface,
148 148
 }};
149 149
 
150 150
 static const struct usb_config_descriptor config = {
151
-    .bLength = USB_DT_CONFIGURATION_SIZE,
152
-    .bDescriptorType = USB_DT_CONFIGURATION,
153
-    .wTotalLength = 0,
154
-    .bNumInterfaces = 2,
155
-    .bConfigurationValue = 1,
156
-    .iConfiguration = 0,
157
-    .bmAttributes = 0x80,
158
-    .bMaxPower = 0x32,
159
-
160
-    .interface = ifaces,
151
+	.bLength = USB_DT_CONFIGURATION_SIZE,
152
+	.bDescriptorType = USB_DT_CONFIGURATION,
153
+	.wTotalLength = 0,
154
+	.bNumInterfaces = 2,
155
+	.bConfigurationValue = 1,
156
+	.iConfiguration = 0,
157
+	.bmAttributes = 0x80,
158
+	.bMaxPower = 0x32,
159
+
160
+	.interface = ifaces,
161 161
 };
162 162
 
163 163
 static const char *usb_strings[] = {
164
-    "flabbergast",
165
-    "CDC-ACM Test",
166
-    "DeMo",
164
+	"flabbergast",
165
+	"CDC-ACM Test",
166
+	"DeMo",
167 167
 };
168 168
 
169 169
 /* Buffer to be used for control requests. */
@@ -172,163 +172,165 @@ uint8_t usbd_control_buffer[128];
172 172
 /* Aux functions */
173 173
 static void led_flip(void) {
174 174
   if(GPIOA_IDR & (1<<15)) {
175
-      GPIOA_BRR = GPIO15;
175
+	  GPIOA_BRR = GPIO15;
176 176
   } else {
177
-      GPIOA_BSRR = GPIO15;
177
+	  GPIOA_BSRR = GPIO15;
178 178
   }
179 179
 }
180 180
 
181 181
 static int cdcacm_control_request(usbd_device *usbd_dev,
182
-    struct usb_setup_data *req, uint8_t **buf, uint16_t *len,
183
-    void (**complete)(usbd_device *usbd_dev, struct usb_setup_data *req))
182
+	struct usb_setup_data *req, uint8_t **buf, uint16_t *len,
183
+	void (**complete)(usbd_device *usbd_dev, struct usb_setup_data *req))
184 184
 {
185
-    (void)complete;
186
-    (void)buf;
187
-    (void)usbd_dev;
188
-
189
-    switch(req->bRequest) {
190
-    case USB_CDC_REQ_SET_CONTROL_LINE_STATE: {
191
-        /*
192
-         * This Linux cdc_acm driver requires this to be implemented
193
-         * even though it's optional in the CDC spec, and we don't
194
-         * advertise it in the ACM functional descriptor.
195
-         */
196
-        char local_buf[10];
197
-        struct usb_cdc_notification *notif = (void *)local_buf;
198
-
199
-        /* We echo signals back to host as notification. */
200
-        notif->bmRequestType = 0xA1;
201
-        notif->bNotification = USB_CDC_NOTIFY_SERIAL_STATE;
202
-        notif->wValue = 0;
203
-        notif->wIndex = 0;
204
-        notif->wLength = 2;
205
-        local_buf[8] = req->wValue & 3;
206
-        local_buf[9] = 0;
207
-        // usbd_ep_write_packet(0x83, buf, 10);
208
-        return 1;
209
-        }
210
-    case USB_CDC_REQ_SET_LINE_CODING:
211
-        if(*len < sizeof(struct usb_cdc_line_coding))
212
-            return 0;
213
-
214
-        return 1;
215
-    }
216
-    return 0;
185
+	(void)complete;
186
+	(void)buf;
187
+	(void)usbd_dev;
188
+
189
+	switch(req->bRequest) {
190
+	case USB_CDC_REQ_SET_CONTROL_LINE_STATE: {
191
+		/*
192
+		 * This Linux cdc_acm driver requires this to be implemented
193
+		 * even though it's optional in the CDC spec, and we don't
194
+		 * advertise it in the ACM functional descriptor.
195
+		 */
196
+		char local_buf[10];
197
+		struct usb_cdc_notification *notif = (void *)local_buf;
198
+
199
+		/* We echo signals back to host as notification. */
200
+		notif->bmRequestType = 0xA1;
201
+		notif->bNotification = USB_CDC_NOTIFY_SERIAL_STATE;
202
+		notif->wValue = 0;
203
+		notif->wIndex = 0;
204
+		notif->wLength = 2;
205
+		local_buf[8] = req->wValue & 3;
206
+		local_buf[9] = 0;
207
+		// usbd_ep_write_packet(0x83, buf, 10);
208
+		return 1;
209
+		}
210
+	case USB_CDC_REQ_SET_LINE_CODING:
211
+		if(*len < sizeof(struct usb_cdc_line_coding))
212
+			return 0;
213
+
214
+		return 1;
215
+	}
216
+	return 0;
217 217
 }
218 218
 
219 219
 static void cdcacm_data_rx_cb(usbd_device *usbd_dev, uint8_t ep)
220 220
 {
221
-    (void)ep;
221
+	(void)ep;
222 222
 
223
-    char buf[64];
224
-    int len = usbd_ep_read_packet(usbd_dev, 0x01, buf, 64);
223
+	char buf[64];
224
+	int len = usbd_ep_read_packet(usbd_dev, 0x01, buf, 64);
225 225
 
226
-    if (len) {
227
-        usbd_ep_write_packet(usbd_dev, 0x82, buf, len);
228
-        buf[len] = 0;
229
-    led_flip();
230
-    }
226
+	if (len) {
227
+		usbd_ep_write_packet(usbd_dev, 0x82, buf, len);
228
+		buf[len] = 0;
229
+	led_flip();
230
+	}
231 231
 }
232 232
 
233 233
 static void cdcacm_set_config(usbd_device *usbd_dev, uint16_t wValue)
234 234
 {
235
-    (void)wValue;
235
+	(void)wValue;
236 236
 
237
-    usbd_ep_setup(usbd_dev, 0x01, USB_ENDPOINT_ATTR_BULK, 64, cdcacm_data_rx_cb);
238
-    usbd_ep_setup(usbd_dev, 0x82, USB_ENDPOINT_ATTR_BULK, 64, NULL);
239
-    usbd_ep_setup(usbd_dev, 0x83, USB_ENDPOINT_ATTR_INTERRUPT, 16, NULL);
237
+	usbd_ep_setup(usbd_dev, 0x01, USB_ENDPOINT_ATTR_BULK, 64, cdcacm_data_rx_cb);
238
+	usbd_ep_setup(usbd_dev, 0x82, USB_ENDPOINT_ATTR_BULK, 64, NULL);
239
+	usbd_ep_setup(usbd_dev, 0x83, USB_ENDPOINT_ATTR_INTERRUPT, 16, NULL);
240 240
 
241
-    usbd_register_control_callback(
242
-                usbd_dev,
243
-                USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE,
244
-                USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT,
245
-                cdcacm_control_request);
241
+	usbd_register_control_callback(
242
+				usbd_dev,
243
+				USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE,
244
+				USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT,
245
+				cdcacm_control_request);
246 246
 }
247 247
 
248 248
 int main(void)
249 249
 {
250
-    usbd_device *usbd_dev;
250
+	usbd_device *usbd_dev;
251 251
 
252 252
 #if defined(BOOTLOADER8K)
253
-#   define SCB_VTOR MMIO32(0xE000ED08)
254
-    SCB_VTOR = (uint32_t) 0x08002000;
253
+#	define SCB_VTOR MMIO32(0xE000ED08)
254
+	SCB_VTOR = (uint32_t) 0x08002000;
255 255
 #endif
256 256
 
257 257
 #if defined(STM32F0)
258
-    rcc_clock_setup_in_hsi_out_48mhz();
259
-    crs_autotrim_usb_enable();
260
-    rcc_set_usbclk_source(RCC_HSI48);
258
+	rcc_clock_setup_in_hsi_out_48mhz();
259
+	crs_autotrim_usb_enable();
260
+	rcc_set_usbclk_source(RCC_HSI48);
261 261
 
262
-    // this is needed for F042 in TSSOP-20 package; USB is on shared pins
263
-    //rcc_periph_clock_enable(RCC_SYSCFG_COMP);
264
-    //SYSCFG_CFGR1 |= SYSCFG_CFGR1_PA11_PA12_RMP;
262
+	// this is needed for F042 in TSSOP-20 package; USB is on shared pins
263
+	//rcc_periph_clock_enable(RCC_SYSCFG_COMP);
264
+	//SYSCFG_CFGR1 |= SYSCFG_CFGR1_PA11_PA12_RMP;
265 265
  
266 266
 #elif defined(STM32L0)
267 267
 
268
-    // libopencm3 clock setup can be a bit ad-hoc, so let's configure manually
269
-    // 32MHz, PLL supplied by the internal HSI16 oscillator
270
-    /* Set the flash latency */
271
-    FLASH_ACR |= FLASH_ACR_LATENCY_1WS;
272
-    /* Turn on HSI16 */
273
-    RCC_CR |= RCC_CR_HSI16ON;
268
+	// libopencm3 clock setup can be a bit ad-hoc, so let's configure manually
269
+	// 32MHz, PLL supplied by the internal HSI16 oscillator
270
+	/* Set the flash latency */
271
+	FLASH_ACR |= FLASH_ACR_LATENCY_1WS;
272
+	/* Turn on HSI16 */
273
+	RCC_CR |= RCC_CR_HSI16ON;
274 274
 	while ((RCC_CR & RCC_CR_HSI16RDY) == 0);
275
-    /* Make sure PLL is off (it should be after reset, but ...) */
276
-    RCC_CR &= ~RCC_CR_PLLON;
275
+	/* Make sure PLL is off (it should be after reset, but ...) */
276
+	RCC_CR &= ~RCC_CR_PLLON;
277 277
 	while (RCC_CR & RCC_CR_PLLRDY);
278
-    /* Set the PLL source to HSI16 */
279
-    RCC_CFGR &= ~(1<<16); // RCC_CFGR_PLLSRC
280
-    /* Set up the PLL */
281
-    uint32_t reg = RCC_CFGR
282
-                   & ~( (RCC_CFGR_PLLMUL_MASK << RCC_CFGR_PLLMUL_SHIFT)
283
-                      | (RCC_CFGR_PLLDIV_MASK << RCC_CFGR_PLLDIV_SHIFT));
284
-    RCC_CFGR = reg | (RCC_CFGR_PLLMUL_MUL4 << RCC_CFGR_PLLMUL_SHIFT)
285
-                   | (RCC_CFGR_PLLDIV_DIV2 << RCC_CFGR_PLLDIV_SHIFT);
286
-    /* Turn on PLL and switch to it */
287
-    RCC_CR |= RCC_CR_PLLON;
288
-    while ((RCC_CR & RCC_CR_PLLRDY) == 0);
289
-    RCC_CFGR |=  RCC_CFGR_SW_PLL;
290
-    /* Set the peripheral clock frequencies used. */
291
-    rcc_ahb_frequency  = 32000000; 
292
-    rcc_apb1_frequency = 32000000;
293
-    rcc_apb2_frequency = 32000000;
294
-    // end of manual clock configuration
295
-
296
-    // Enable VREFINT reference for HSI48
297
-    rcc_periph_clock_enable(RCC_SYSCFG);
298
-    SYSCFG_CFGR3 |= SYSCFG_CFGR3_ENREF_HSI48;
299
-
300
-    rcc_set_hsi48_source_rc48();
301
-    crs_autotrim_usb_enable();
302
-
303
-    rcc_osc_on(RCC_HSI48);
304
-    rcc_wait_for_osc_ready(RCC_HSI48);
305
-
306
-    /* MCO on PA9, to verify MCU speed with a scope */
307
-    gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO9);
308
-    gpio_set_af(GPIOA, GPIO_AF0, GPIO9);
309
-    RCC_CFGR |= (RCC_CFGR_MCO_SYSCLK << RCC_CFGR_MCO_SHIFT) | (RCC_CFGR_MCOPRE_DIV16 << 28);
278
+	/* Set the PLL source to HSI16 */
279
+	RCC_CFGR &= ~(1<<16); // RCC_CFGR_PLLSRC
280
+	/* Set up the PLL */
281
+	uint32_t reg = RCC_CFGR
282
+				   & ~( (RCC_CFGR_PLLMUL_MASK << RCC_CFGR_PLLMUL_SHIFT)
283
+					  | (RCC_CFGR_PLLDIV_MASK << RCC_CFGR_PLLDIV_SHIFT));
284
+	RCC_CFGR = reg | (RCC_CFGR_PLLMUL_MUL4 << RCC_CFGR_PLLMUL_SHIFT)
285
+				   | (RCC_CFGR_PLLDIV_DIV2 << RCC_CFGR_PLLDIV_SHIFT);
286
+	/* Turn on PLL and switch to it */
287
+	RCC_CR |= RCC_CR_PLLON;
288
+	while ((RCC_CR & RCC_CR_PLLRDY) == 0);
289
+	RCC_CFGR |=  RCC_CFGR_SW_PLL;
290
+	/* Set the peripheral clock frequencies used. */
291
+	rcc_ahb_frequency  = 32000000; 
292
+	rcc_apb1_frequency = 32000000;
293
+	rcc_apb2_frequency = 32000000;
294
+	// end of manual clock configuration
295
+
296
+	// Enable VREFINT reference for HSI48
297
+	rcc_periph_clock_enable(RCC_SYSCFG);
298
+	SYSCFG_CFGR3 |= SYSCFG_CFGR3_ENREF_HSI48;
299
+
300
+	rcc_set_hsi48_source_rc48();
301
+	crs_autotrim_usb_enable();
302
+
303
+	rcc_osc_on(RCC_HSI48);
304
+	rcc_wait_for_osc_ready(RCC_HSI48);
305
+
306
+	/* MCO on PA9, to verify MCU speed with a scope */
307
+	gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO9);
308
+	gpio_set_af(GPIOA, GPIO_AF0, GPIO9);
309
+	RCC_CFGR |= (RCC_CFGR_MCO_SYSCLK << RCC_CFGR_MCO_SHIFT) | (RCC_CFGR_MCOPRE_DIV16 << 28);
310 310
 
311 311
 #else
312
-    #error "Edit the sources and do the clock setup!"
312
+	#error "Edit the sources and do the clock setup!"
313 313
 #endif
314 314
 
315
-    rcc_periph_clock_enable(RCC_GPIOA);
316
-    gpio_mode_setup(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO15); // LED
315
+	rcc_periph_clock_enable(RCC_GPIOA);
316
+	gpio_mode_setup(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO15); // LED
317 317
 	gpio_mode_setup(GPIOA, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO1);   // button, has external pull-down
318 318
 
319
-    usbd_dev = usbd_init(&st_usbfs_v2_usb_driver, &dev, &config, usb_strings, 3, usbd_control_buffer, sizeof(usbd_control_buffer));
319
+	usbd_dev = usbd_init(&st_usbfs_v2_usb_driver, &dev, &config, usb_strings, 3, usbd_control_buffer, sizeof(usbd_control_buffer));
320 320
 
321
-    usbd_register_set_config_callback(usbd_dev, cdcacm_set_config);
321
+	usbd_register_set_config_callback(usbd_dev, cdcacm_set_config);
322 322
 
323
-    char greeting[16] = "hello, world\r\n";
323
+	char greeting[16] = "hello, world\r\n";
324 324
 
325
-    while (1) {
326
-        usbd_poll(usbd_dev);
325
+	while (1) {
326
+		usbd_poll(usbd_dev);
327 327
 		if (gpio_get(GPIOA, GPIO1)) {
328
-            usbd_ep_write_packet(usbd_dev, 0x82, greeting, 15);
328
+			usbd_ep_write_packet(usbd_dev, 0x82, greeting, 15);
329 329
 			for (uint32_t i = 0; i < 2000000; i++) {	/* Wait a bit, cheap "debounce" */
330 330
 				__asm__("nop");
331 331
 			}
332
-        }
333
-    }
332
+		}
333
+	}
334 334
 }
335
+
336
+// vim: tabstop=4:shiftwidth=4:noexpandtab

+ 29
- 0
usb_dfu/Makefile View File

@@ -0,0 +1,29 @@
1
+##
2
+## This file is part of the libopencm3 project.
3
+##
4
+## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
5
+##
6
+## This library is free software: you can redistribute it and/or modify
7
+## it under the terms of the GNU Lesser General Public License as published by
8
+## the Free Software Foundation, either version 3 of the License, or
9
+## (at your option) any later version.
10
+##
11
+## This library is distributed in the hope that it will be useful,
12
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
+## GNU Lesser General Public License for more details.
15
+##
16
+## You should have received a copy of the GNU Lesser General Public License
17
+## along with this library.  If not, see <http://www.gnu.org/licenses/>.
18
+##
19
+
20
+BINARY = usbdfu
21
+
22
+# OBJS += hardfault.o
23
+
24
+OPENCM3_DIR=../libopencm3
25
+LDSCRIPT = $(OPENCM3_DIR)/lib/stm32/l0/stm32l0xx8.ld
26
+CSTD = -std=gnu99
27
+
28
+include ../common.l0.mk
29
+

+ 41
- 0
usb_dfu/README.md View File

@@ -0,0 +1,41 @@
1
+# README
2
+
3
+This example implements a USB Device Firmware Upgrade (DFU) bootloader
4
+to demonstrate the use of the USB device stack.
5
+
6
+It is intended to run on STM32L0 chips; this particular instance on STM32L052C8Tx.
7
+
8
+## Usage notes
9
+
10
+The bootloader has been tested on a STM32L052C8T7, it takes 8kB of the flash space. It has been tested with [dfu-util] 0.9 on Mac OS X. The usual command is something like
11
+
12
+        dfu-util -s 0x8002000 -D <binary_fw>
13
+
14
+The "user firmware" needs to be compiled to start at 0x8002000 (i.e. the vector table should be there), and set `SCB_VTOR` to 0x8002000 immediately after starting.
15
+
16
+## Implementation notes
17
+
18
+To modify for another chip, the particular places to check are:
19
+
20
+ * `MCU_PAGE_SIZE` define: check the reference manual for page size (usually in the section "NVM organization"). The code assumes that the page size is the same for the whole part where the bootloader will write (i.e. from 0x8002000 to the end of flash).
21
+ * The dfuse string in `usb_strings`. This describes the various parts of the flash, and the DfuSe app or dfu-util will use this to determine e.g. the page size, or which parts of the flash are writable.
22
+ * The clock setup in `main()`.
23
+ * The easy bits in `main()`: which pin to be checked (and how) for forcing the bootloader, which pin to blink on and how fast to blink.
24
+
25
+ * The `PROGRAM_BY_HALF_PAGE` define decides whether to write to flash word-by-word, or a half-a-page at once.
26
+ * `hardfault.c` hooks into the hard fault handler, and defines some variables to make it easy(er) to figure out what caused the fault, in e.g. gdb. To enable this, just uncomment it in `OBJS` in the `Makefile`.
27
+
28
+## Beware
29
+
30
+The programming speed is about 3.2Kb/sec (compared to 1440 bytes/sec over the ROM USART bootloader using 115200 baud; and to 3K-6K/sec via SWD). It is achieved by pretending (over DFU) that the page size is 1K (instead of the internal 128 bytes) - the bottleneck turned out to be the USB.
31
+
32
+Also it uses writing-half-a-page-at-once from RAM, instead of the (slower) option of writing word-by-word. (With word-by-word, pretending 1K blocks, it's 950 bytes/sec, with word-by-word OR half-a-page, but native 128 byte blocks. it's 420 bytes/sec).
33
+
34
+## Credits
35
+
36
+[Original code]: Copyright (C) 2010 Gareth McMullin <gareth@blacksphere.co.nz>
37
+
38
+Modifications to run on STM32L0: (C) 2016 flabbergast <flabbergast@drak.xyz>
39
+
40
+[Original code]: https://github.com/libopencm3/libopencm3-examples/tree/8924042d2acd8b0a9dd7c307a3ea925cca87d554/examples/stm32/f1/other/usb_dfu
41
+[dfu-util]: http://dfu-util.sourceforge.net/

+ 89
- 0
usb_dfu/hardfault.c View File

@@ -0,0 +1,89 @@
1
+/**
2
+ * HardFault_HandlerAsm:
3
+ * Alternative Hard Fault handler to help debug the reason for a fault.
4
+ * To use, edit the vector table to reference this function in the HardFault vector
5
+ * This code is suitable for Cortex-M3 and Cortex-M0 cores
6
+ */
7
+
8
+#pragma weak hard_fault_handler = HardFault_Handler
9
+ 
10
+// Use the 'naked' attribute so that C stacking is not used.
11
+__attribute__((naked))
12
+void HardFault_Handler(void){
13
+        /*
14
+         * Get the appropriate stack pointer, depending on our mode,
15
+         * and use it as the parameter to the C handler. This function
16
+         * will never return
17
+         */
18
+         // ".syntax unified\n"
19
+        __asm(  
20
+                        "MOVS   R0, #4  \n"
21
+                        "MOV    R1, LR  \n"
22
+                        "TST    R0, R1  \n"
23
+                        "BEQ    _MSP    \n"
24
+                        "MRS    R0, PSP \n"
25
+                        "B      HardFault_HandlerC      \n"
26
+                "_MSP:  \n"
27
+                        "MRS    R0, MSP \n"
28
+                        "B      HardFault_HandlerC      \n"
29
+                );
30
+        // ".syntax divided\n"
31
+}
32
+
33
+/**
34
+ * HardFaultHandler_C:
35
+ * This is called from the HardFault_HandlerAsm with a pointer the Fault stack
36
+ * as the parameter. We can then read the values from the stack and place them
37
+ * into local variables for ease of reading.
38
+ * We then read the various Fault Status and Address Registers to help decode
39
+ * cause of the fault.
40
+ * The function ends with a BKPT instruction to force control back into the debugger
41
+ */
42
+void HardFault_HandlerC(unsigned long *hardfault_args){
43
+        volatile unsigned long stacked_r0 ;
44
+        volatile unsigned long stacked_r1 ;
45
+        volatile unsigned long stacked_r2 ;
46
+        volatile unsigned long stacked_r3 ;
47
+        volatile unsigned long stacked_r12 ;
48
+        volatile unsigned long stacked_lr ;
49
+        volatile unsigned long stacked_pc ;
50
+        volatile unsigned long stacked_psr ;
51
+        volatile unsigned long _CFSR ;
52
+        volatile unsigned long _HFSR ;
53
+        volatile unsigned long _DFSR ;
54
+        volatile unsigned long _AFSR ;
55
+        volatile unsigned long _BFAR ;
56
+        volatile unsigned long _MMAR ;
57
+
58
+        stacked_r0 = ((unsigned long)hardfault_args[0]) ;
59
+        stacked_r1 = ((unsigned long)hardfault_args[1]) ;
60
+        stacked_r2 = ((unsigned long)hardfault_args[2]) ;
61
+        stacked_r3 = ((unsigned long)hardfault_args[3]) ;
62
+        stacked_r12 = ((unsigned long)hardfault_args[4]) ;
63
+        stacked_lr = ((unsigned long)hardfault_args[5]) ;
64
+        stacked_pc = ((unsigned long)hardfault_args[6]) ;
65
+        stacked_psr = ((unsigned long)hardfault_args[7]) ;
66
+
67
+        // Configurable Fault Status Register
68
+        // Consists of MMSR, BFSR and UFSR
69
+        _CFSR = (*((volatile unsigned long *)(0xE000ED28))) ;   
70
+                                                                                        
71
+        // Hard Fault Status Register
72
+        _HFSR = (*((volatile unsigned long *)(0xE000ED2C))) ;
73
+
74
+        // Debug Fault Status Register
75
+        _DFSR = (*((volatile unsigned long *)(0xE000ED30))) ;
76
+
77
+        // Auxiliary Fault Status Register
78
+        _AFSR = (*((volatile unsigned long *)(0xE000ED3C))) ;
79
+
80
+        // Read the Fault Address Registers. These may not contain valid values.
81
+        // Check BFARVALID/MMARVALID to see if they are valid values
82
+        // MemManage Fault Address Register
83
+        _MMAR = (*((volatile unsigned long *)(0xE000ED34))) ;
84
+        // Bus Fault Address Register
85
+        _BFAR = (*((volatile unsigned long *)(0xE000ED38))) ;
86
+
87
+        __asm("BKPT #0\n") ; // Break into the debugger
88
+
89
+}

+ 101
- 0
usb_dfu/lib-flash-from-ram.patch View File

@@ -0,0 +1,101 @@
1
+diff --git a/include/libopencm3/stm32/l0/flash.h b/include/libopencm3/stm32/l0/flash.h
2
+index 3716300..c2179c3 100644
3
+--- a/include/libopencm3/stm32/l0/flash.h
4
++++ b/include/libopencm3/stm32/l0/flash.h
5
+@@ -70,6 +70,14 @@
6
+ #define FLASH_OPTR_RDPRT_LEVEL_1	(0x00)
7
+ #define FLASH_OPTR_RDPRT_LEVEL_2	(0xcc)
8
+ 
9
++/* --- RAM functions workaround -------------------------------------------- */
10
++
11
++#if defined(L0_FLASH_FNS_FROM_RAM) && L0_FLASH_FNS_FROM_RAM
12
++#define __FROM_RAM __attribute__((__long_call__,section(".data")))
13
++#else
14
++#define __FROM_RAM
15
++#endif
16
++
17
+ /* --- Function prototypes ------------------------------------------------- */
18
+ 
19
+ BEGIN_DECLS
20
+diff --git a/lib/stm32/l0/Makefile b/lib/stm32/l0/Makefile
21
+index 8ed6779..a29a5ad 100644
22
+--- a/lib/stm32/l0/Makefile
23
++++ b/lib/stm32/l0/Makefile
24
+@@ -20,6 +20,8 @@
25
+ LIBNAME		= libopencm3_stm32l0
26
+ SRCLIBDIR	?= ../..
27
+ 
28
++FLASH_FROM_RAM ?= 0
29
++
30
+ PREFIX		?= arm-none-eabi
31
+ #PREFIX		?= arm-elf
32
+ CC		= $(PREFIX)-gcc
33
+@@ -30,7 +32,8 @@ TGT_CFLAGS	= -Os \
34
+ 		  -Wundef -Wshadow \
35
+ 		  -I../../../include -fno-common \
36
+ 		  -mcpu=cortex-m0plus $(FP_FLAGS) -mthumb -Wstrict-prototypes \
37
+-		  -ffunction-sections -fdata-sections -MD -DSTM32L0
38
++		  -ffunction-sections -fdata-sections -MD -DSTM32L0 \
39
++		  -DL0_FLASH_FNS_FROM_RAM=$(FLASH_FROM_RAM)
40
+ TGT_CFLAGS      += $(DEBUG_FLAGS)
41
+ 
42
+ ARFLAGS		= rcs
43
+diff --git a/lib/stm32/l0/flash.c b/lib/stm32/l0/flash.c
44
+index ec7280a..9e2b34f 100644
45
+--- a/lib/stm32/l0/flash.c
46
++++ b/lib/stm32/l0/flash.c
47
+@@ -93,13 +93,15 @@ Warning: this function MUST be executed from RAM.
48
+ @param[in] data Pointer data to write
49
+ */
50
+ 
51
+-void flash_program_half_page(uint32_t address, uint32_t *data, uint16_t page_size)
52
++__FROM_RAM void flash_program_half_page(uint32_t address, uint32_t *data, uint16_t page_size)
53
+ {
54
+ 	uint16_t i;
55
+ 
56
++	while (FLASH_SR & FLASH_SR_BSY);
57
++
58
+ 	FLASH_PECR |= FLASH_PECR_PROG | FLASH_PECR_FPRG;
59
+ 
60
+-	for (i = 0; i < ((page_size/2) * 4); i+=4, data++) {
61
++	for (i = 0; i < (page_size/2); i+=4, data++) {
62
+ 		MMIO32(address + i) = *data;
63
+ 	}
64
+ 
65
+@@ -151,7 +153,7 @@ memory. The information block is unaffected.
66
+ Warning: this function MUST be executed from RAM.
67
+ */
68
+ 
69
+-void flash_erase_all_pages(void)
70
++__FROM_RAM void flash_erase_all_pages(void)
71
+ {
72
+   
73
+ 	/* (1) Check if the read protection is not level 2 */
74
+@@ -173,7 +175,8 @@ void flash_erase_all_pages(void)
75
+ 	/* Should check that the memory was erased here */
76
+ 
77
+ 	/* (6) Lock the NVM by setting the PELOCK bit */
78
+-	flash_lock_pecr();
79
++	while (FLASH_SR & FLASH_SR_BSY);
80
++	FLASH_PECR |= FLASH_PECR_PELOCK;
81
+ 
82
+ 	/* Infinite loop */ 
83
+ 	while (1);
84
+@@ -191,7 +194,7 @@ Warning: this function MUST be executed from RAM.
85
+ @param[in] address Address of option byte from @ref flash_options.
86
+ */
87
+ 
88
+-void flash_erase_option_byte(uint32_t address)
89
++__FROM_RAM void flash_erase_option_byte(uint32_t address)
90
+ {
91
+ 	FLASH_PECR |= FLASH_PECR_ERASE;
92
+ 
93
+@@ -221,7 +224,7 @@ Warning: this function MUST be executed from RAM.
94
+ @param[in] data value to write
95
+ */
96
+ 
97
+-void flash_program_option_byte(uint32_t address, uint16_t data)
98
++__FROM_RAM void flash_program_option_byte(uint32_t address, uint16_t data)
99
+ {
100
+ 	MMIO32(address) = (uint32_t)((~data << 16) | data);
101
+ 

+ 433
- 0
usb_dfu/usbdfu.c View File

@@ -0,0 +1,433 @@
1
+/*
2
+ * This file is part of the libopencm3 project.
3
+ *
4
+ * Copyright (C) 2010 Gareth McMullin <gareth@blacksphere.co.nz>
5
+ *
6
+ * This library is free software: you can redistribute it and/or modify
7
+ * it under the terms of the GNU Lesser General Public License as published by
8
+ * the Free Software Foundation, either version 3 of the License, or
9
+ * (at your option) any later version.
10
+ *
11
+ * This library is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
+ * GNU Lesser General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU Lesser General Public License
17
+ * along with this library.  If not, see <http://www.gnu.org/licenses/>.
18
+ */
19
+
20
+#include <string.h>
21
+#include <libopencm3/stm32/rcc.h>
22
+#include <libopencm3/stm32/gpio.h>
23
+#include <libopencm3/stm32/syscfg.h>
24
+#include <libopencm3/stm32/crs.h>
25
+#include <libopencm3/stm32/flash.h>
26
+#include <libopencm3/cm3/scb.h>
27
+#include <libopencm3/usb/usbd.h>
28
+#include <libopencm3/usb/dfu.h>
29
+
30
+#define APP_ADDRESS	0x08002000
31
+
32
+#define PROGRAM_BY_HALF_PAGE
33
+
34
+#define DFU_PACKET_SIZE 1024
35
+#define MCU_PAGE_SIZE 128
36
+/* Note: DFU_PACKET_SIZE has to be an integer multiple of MCU_PAGE_SIZE */
37
+/*       DFU_PACKET_SIZE needs to match the DfuSe string below */
38
+
39
+/* This is supposed to be in libopencm3/lib/stm32/l0/flash.c but isn't */
40
+void flash_erase_page(uint32_t address);
41
+
42
+#if defined(PROGRAM_BY_HALF_PAGE)
43
+
44
+#define __FROM_RAM __attribute__((__long_call__, section(".data"),optimize("Os")))
45
+
46
+void flash_half_page(uint32_t address, uint32_t *data);
47
+__FROM_RAM void flash_half_page(uint32_t address, uint32_t *data)
48
+{
49
+	uint16_t i;
50
+
51
+	__asm__ volatile ("CPSID I\n");
52
+
53
+	FLASH_PECR |= FLASH_PECR_PROG | FLASH_PECR_FPRG;
54
+
55
+	i = 0;
56
+	while(i < (MCU_PAGE_SIZE/8)) { /* half a page, 4byte words */
57
+		/* Address doesn't need to be increased ... */
58
+		MMIO32(address) = *data;
59
+		data++;
60
+		i++;
61
+	}
62
+
63
+	while (FLASH_SR & FLASH_SR_BSY);
64
+
65
+	__asm__ volatile ("CPSIE I\n");
66
+
67
+	if ((FLASH_SR & FLASH_SR_EOP) != 0) {
68
+		FLASH_SR = FLASH_SR_EOP;
69
+	} /* else error */
70
+
71
+	FLASH_PECR &= ~(FLASH_PECR_PROG | FLASH_PECR_FPRG);
72
+}
73
+
74
+#endif /* PROGRAM_BY_HALF_PAGE */
75
+
76
+/* Commands sent with wBlockNum == 0 as per ST implementation. */
77
+#define CMD_SETADDR	0x21
78
+#define CMD_ERASE	0x41
79
+
80
+uint8_t usbd_control_buffer[DFU_PACKET_SIZE];
81
+
82
+static enum dfu_state usbdfu_state = STATE_DFU_IDLE;
83
+
84
+static struct {
85
+	uint8_t buf[sizeof(usbd_control_buffer)];
86
+	uint16_t len;
87
+	uint32_t addr;
88
+	uint16_t blocknum;
89
+} prog;
90
+
91
+const struct usb_device_descriptor dev = {
92
+	.bLength = USB_DT_DEVICE_SIZE,
93
+	.bDescriptorType = USB_DT_DEVICE,
94
+	.bcdUSB = 0x0200,
95
+	.bDeviceClass = 0,
96
+	.bDeviceSubClass = 0,
97
+	.bDeviceProtocol = 0,
98
+	.bMaxPacketSize0 = 64,
99
+	.idVendor = 0x0483,
100
+	.idProduct = 0xDF11,
101
+	.bcdDevice = 0x0200,
102
+	.iManufacturer = 1,
103
+	.iProduct = 2,
104
+	.iSerialNumber = 3,
105
+	.bNumConfigurations = 1,
106
+};
107
+
108
+const struct usb_dfu_descriptor dfu_function = {
109
+	.bLength = sizeof(struct usb_dfu_descriptor),
110
+	.bDescriptorType = DFU_FUNCTIONAL,
111
+	.bmAttributes = USB_DFU_CAN_DOWNLOAD | USB_DFU_WILL_DETACH,
112
+	.wDetachTimeout = 255,
113
+	.wTransferSize = DFU_PACKET_SIZE,
114
+	.bcdDFUVersion = 0x011A,
115
+};
116
+
117
+const struct usb_interface_descriptor iface = {
118
+	.bLength = USB_DT_INTERFACE_SIZE,
119
+	.bDescriptorType = USB_DT_INTERFACE,
120
+	.bInterfaceNumber = 0,
121
+	.bAlternateSetting = 0,
122
+	.bNumEndpoints = 0,
123
+	.bInterfaceClass = 0xFE, /* Device Firmware Upgrade */
124
+	.bInterfaceSubClass = 1,
125
+	.bInterfaceProtocol = 2,
126
+
127
+	/* The ST Microelectronics DfuSe application needs this string.
128
+	 * The format isn't documented... */
129
+	.iInterface = 4,
130
+
131
+	.extra = &dfu_function,
132
+	.extralen = sizeof(dfu_function),
133
+};
134
+
135
+const struct usb_interface ifaces[] = {{
136
+	.num_altsetting = 1,
137
+	.altsetting = &iface,
138
+}};
139
+
140
+const struct usb_config_descriptor config = {
141
+	.bLength = USB_DT_CONFIGURATION_SIZE,
142
+	.bDescriptorType = USB_DT_CONFIGURATION,
143
+	.wTotalLength = 0,
144
+	.bNumInterfaces = 1,
145
+	.bConfigurationValue = 1,
146
+	.iConfiguration = 0,
147
+	.bmAttributes = 0xC0,
148
+	.bMaxPower = 0x32,
149
+
150
+	.interface = ifaces,
151
+};
152
+
153
+static const char *usb_strings[] = {
154
+	"flabbergast",
155
+	"L052 DFU Bootloader",
156
+	"STM32L052C8Tx",
157
+	/* This string is used by ST Microelectronics' DfuSe utility. */
158
+	"@Internal Flash   /0x08000000/8*001Ka,56*001Kg"
159
+};
160
+
161
+/* Notes about the dfuse string above:
162
+ * /<start_address>/<number>*<page_size><multiplier><memtype>
163
+ *  <number>: how many pages
164
+ *  <page_size>: self explanatory
165
+ *  <multiplier>: 'B'(ytes), 'K'(ilobytes), 'M'(egabytes)
166
+ *  <memtype>: the bottom three bits are significant:
167
+ *             writeable|erasable|readable
168
+ * subsequent blocks separated by commas
169
+ *
170
+ * Using the internal page size: "@Internal Flash   /0x08000000/64*128Ba,448*128Bg"
171
+ * Using 1K blocks: "@Internal Flash   /0x08000000/8*001Ka,56*001Kg"
172
+ */
173
+
174
+static uint8_t usbdfu_getstatus(uint32_t *bwPollTimeout)
175
+{
176
+	switch (usbdfu_state) {
177
+	case STATE_DFU_DNLOAD_SYNC:
178
+		usbdfu_state = STATE_DFU_DNBUSY;
179
+		*bwPollTimeout = 100;
180
+		return DFU_STATUS_OK;
181
+	case STATE_DFU_MANIFEST_SYNC:
182
+		/* Device will reset when read is complete. */
183
+		usbdfu_state = STATE_DFU_MANIFEST;
184
+		return DFU_STATUS_OK;
185
+	default:
186
+		return DFU_STATUS_OK;
187
+	}
188
+}
189
+
190
+static void usbdfu_getstatus_complete(usbd_device *usbd_dev, struct usb_setup_data *req)
191
+{
192
+	int i;
193
+	(void)req;
194
+	(void)usbd_dev;
195
+
196
+	switch (usbdfu_state) {
197
+	case STATE_DFU_DNBUSY:
198
+		flash_unlock();
199
+		if (prog.blocknum == 0) {
200
+			switch (prog.buf[0]) {
201
+			/* code to protect the bootloader? */
202
+			case CMD_ERASE:
203
+				{
204
+					uint32_t *dat = (uint32_t *)(prog.buf + 1);
205
+					i = 0;
206
+					while ( i*MCU_PAGE_SIZE < DFU_PACKET_SIZE ) {
207
+						flash_erase_page(*dat + i*MCU_PAGE_SIZE);
208
+						i++;
209
+					}
210
+				}
211
+			case CMD_SETADDR:
212
+				{
213
+					uint32_t *dat = (uint32_t *)(prog.buf + 1);
214
+					prog.addr = *dat;
215
+				}
216
+			}
217
+		} else {
218
+			uint32_t baseaddr = prog.addr + ((prog.blocknum - 2) *
219
+					   dfu_function.wTransferSize);
220
+#if defined(PROGRAM_BY_HALF_PAGE)
221
+			for (i = 0; i < prog.len; i += (MCU_PAGE_SIZE/2)) {
222
+				uint32_t *dat = (uint32_t *)(prog.buf + i);
223
+				flash_half_page(baseaddr+i, dat);
224
+			}
225
+#else
226
+			for (i = 0; i < prog.len; i += 4) {
227
+				uint32_t *dat = (uint32_t *)(prog.buf + i);
228
+				flash_program_word(baseaddr + i, *dat);
229
+			}
230
+#endif /* PROGRAM_BY_HALF_PAGE */
231
+		}
232
+		flash_lock();
233
+
234
+		/* Jump straight to dfuDNLOAD-IDLE, skipping dfuDNLOAD-SYNC. */
235
+		usbdfu_state = STATE_DFU_DNLOAD_IDLE;
236
+		return;
237
+	case STATE_DFU_MANIFEST:
238
+		/* USB device must detach, we just reset... */
239
+		scb_reset_system();
240
+		return; /* Will never return. */
241
+	default:
242
+		return;
243
+	}
244
+}
245
+
246
+static int usbdfu_control_request(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf,
247
+		uint16_t *len, void (**complete)(usbd_device *usbd_dev, struct usb_setup_data *req))
248
+{
249
+	(void)usbd_dev;
250
+
251
+	if ((req->bmRequestType & 0x7F) != 0x21)
252
+		return 0; /* Only accept class request. */
253
+
254
+	switch (req->bRequest) {
255
+	case DFU_DNLOAD:
256
+		if ((len == NULL) || (*len == 0)) {
257
+			usbdfu_state = STATE_DFU_MANIFEST_SYNC;
258
+			return 1;
259
+		} else {
260
+			/* Copy download data for use on GET_STATUS. */
261
+			prog.blocknum = req->wValue;
262
+			prog.len = *len;
263
+			memcpy(prog.buf, *buf, *len);
264
+			usbdfu_state = STATE_DFU_DNLOAD_SYNC;
265
+			return 1;
266
+		}
267
+	case DFU_CLRSTATUS:
268
+		/* Clear error and return to dfuIDLE. */
269
+		if (usbdfu_state == STATE_DFU_ERROR)
270
+			usbdfu_state = STATE_DFU_IDLE;
271
+		return 1;
272
+	case DFU_ABORT:
273
+		/* Abort returns to dfuIDLE state. */
274
+		usbdfu_state = STATE_DFU_IDLE;
275
+		return 1;
276
+	case DFU_UPLOAD:
277
+		/* Upload not supported for now. */
278
+		return 0;
279
+	case DFU_GETSTATUS: {
280
+		uint32_t bwPollTimeout = 0; /* 24-bit integer in DFU class spec */
281
+		(*buf)[0] = usbdfu_getstatus(&bwPollTimeout);
282
+		(*buf)[1] = bwPollTimeout & 0xFF;
283
+		(*buf)[2] = (bwPollTimeout >> 8) & 0xFF;
284
+		(*buf)[3] = (bwPollTimeout >> 16) & 0xFF;
285
+		(*buf)[4] = usbdfu_state;
286
+		(*buf)[5] = 0; /* iString not used here */
287
+		*len = 6;
288
+		*complete = usbdfu_getstatus_complete;
289
+		return 1;
290
+		}
291
+	case DFU_GETSTATE:
292
+		/* Return state with no state transision. */
293
+		*buf[0] = usbdfu_state;
294
+		*len = 1;
295
+		return 1;
296
+	}
297
+
298
+	return 0;
299
+}
300
+
301
+static void usbdfu_set_config(usbd_device *usbd_dev, uint16_t wValue)
302
+{
303
+	(void)wValue;
304
+
305
+	usbd_register_control_callback(
306
+				usbd_dev,
307
+				USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE,
308
+				USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT,
309
+				usbdfu_control_request);
310
+}
311
+
312
+
313
+/* This is for some reason missing from libopencm3/l0 flash.c
314
+ * (I thought it was in the pull request I've done for l0 but
315
+ *  apparently not.)
316
+ */
317
+/*---------------------------------------------------------------------------*/
318
+/** @brief Erase a Page of FLASH
319
+
320
+This performs all operations necessary to erase a page in FLASH memory.
321
+The page should be checked to ensure that it was properly erased. A page must
322
+first be fully erased before attempting to program it.
323
+
324
+Note that the page sizes differ between devices. See the reference manual or
325
+the FLASH programming manual for details.
326
+
327
+@param[in] address Memory address of the first word on the page to be erased.
328
+*/
329
+__FROM_RAM void flash_erase_page(uint32_t address)
330
+{
331
+	while (FLASH_SR & FLASH_SR_BSY);
332
+
333
+	FLASH_PECR |= FLASH_PECR_ERASE | FLASH_PECR_PROG;
334
+
335
+	MMIO32(address) = (uint32_t)0;
336
+
337
+	while (FLASH_SR & FLASH_SR_BSY);
338
+
339
+	if ((FLASH_SR & FLASH_SR_EOP) != 0) {
340
+		FLASH_SR = FLASH_SR_EOP;
341
+	} /* else error */
342
+
343
+	FLASH_PECR &= ~(FLASH_PECR_ERASE | FLASH_PECR_PROG);
344
+}
345
+
346
+/* End of the bit that's supposed to be in libopencm3/lib/stm32/l0/flash.c */
347
+
348
+
349
+int main(void)
350
+{
351
+	usbd_device *usbd_dev;
352
+	uint32_t k;
353
+
354
+	rcc_periph_clock_enable(RCC_GPIOB);
355
+
356
+	gpio_mode_setup(GPIOB, GPIO_MODE_INPUT, GPIO_PUPD_PULLUP, GPIO3);
357
+
358
+	if (gpio_get(GPIOB, GPIO3)) {
359
+		/* Boot the application if it's valid. */
360
+		if ((*(volatile uint32_t *)APP_ADDRESS & 0x2FFE0000) == 0x20000000) {
361
+			/* Set vector table base address. */
362
+			SCB_VTOR = APP_ADDRESS & 0xFFFF;
363
+			/* Initialise master stack pointer. */
364
+			asm volatile("msr msp, %0"::"g"
365
+					 (*(volatile uint32_t *)APP_ADDRESS));
366
+			/* Jump to application. */
367
+			(*(void (**)())(APP_ADDRESS + 4))();
368
+		}
369
+	}
370
+
371
+    // libopencm3 clock setup can be a bit ad-hoc, so let's configure "manually"
372
+    // 32MHz, PLL supplied by the internal HSI16 oscillator
373
+    /* Set the flash latency */
374
+    FLASH_ACR |= FLASH_ACR_LATENCY_1WS;
375
+    /* Turn on HSI16 */
376
+    RCC_CR |= RCC_CR_HSI16ON;
377
+	while ((RCC_CR & RCC_CR_HSI16RDY) == 0);
378
+    /* Make sure PLL is off (it should be after reset, but ...) */
379
+    RCC_CR &= ~RCC_CR_PLLON;
380
+	while (RCC_CR & RCC_CR_PLLRDY);
381
+    /* Set the PLL source to HSI16 */
382
+    RCC_CFGR &= ~(1<<16); // RCC_CFGR_PLLSRC
383
+    /* Set up the PLL */
384
+    uint32_t reg = RCC_CFGR
385
+                   & ~( (RCC_CFGR_PLLMUL_MASK << RCC_CFGR_PLLMUL_SHIFT)
386
+                      | (RCC_CFGR_PLLDIV_MASK << RCC_CFGR_PLLDIV_SHIFT));
387
+    RCC_CFGR = reg | (RCC_CFGR_PLLMUL_MUL4 << RCC_CFGR_PLLMUL_SHIFT)
388
+                   | (RCC_CFGR_PLLDIV_DIV2 << RCC_CFGR_PLLDIV_SHIFT);
389
+    /* Turn on PLL and switch to it */
390
+    RCC_CR |= RCC_CR_PLLON;
391
+    while ((RCC_CR & RCC_CR_PLLRDY) == 0);
392
+    RCC_CFGR |=  RCC_CFGR_SW_PLL;
393
+    /* Set the peripheral clock frequencies used. */
394
+    rcc_ahb_frequency  = 32000000; 
395
+    rcc_apb1_frequency = 32000000;
396
+    rcc_apb2_frequency = 32000000;
397
+    /* end of "manual" clock setup */
398
+
399
+	/* Enable VREFINT reference for HSI48 */
400
+	rcc_periph_clock_enable(RCC_SYSCFG);
401
+	SYSCFG_CFGR3 |= SYSCFG_CFGR3_ENREF_HSI48;
402
+
403
+	rcc_set_hsi48_source_rc48();
404
+	crs_autotrim_usb_enable();
405
+
406
+	rcc_osc_on(RCC_HSI48);
407
+	rcc_wait_for_osc_ready(RCC_HSI48);
408
+
409
+	/* MCO on PA9, to verify MCU speed with a scope */
410
+	gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO9);
411
+	gpio_set_af(GPIOA, GPIO_AF0, GPIO9);
412
+	RCC_CFGR |= (RCC_CFGR_MCO_SYSCLK << RCC_CFGR_MCO_SHIFT) | (RCC_CFGR_MCOPRE_DIV16 << 28);
413
+
414
+    /* for the LED */
415
+	rcc_periph_clock_enable(RCC_GPIOA);
416
+
417
+	usbd_dev = usbd_init(&st_usbfs_v2_usb_driver, &dev, &config, usb_strings, 4, usbd_control_buffer, sizeof(usbd_control_buffer));
418
+	usbd_register_set_config_callback(usbd_dev, usbdfu_set_config);
419
+
420
+	gpio_mode_setup(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO15);
421
+
422
+	k = 0;
423
+
424
+	while (1) {
425
+		usbd_poll(usbd_dev);
426
+		if(++k == 10000) {
427
+			k = 0;
428
+			gpio_toggle(GPIOA, GPIO15);
429
+		}
430
+	}
431
+}
432
+
433
+// vim: tabstop=4:shiftwidth=4:noexpandtab

Loading…
Cancel
Save