diff --git a/stm32/aioc-fw/.cproject b/stm32/aioc-fw/.cproject
index 84c280b..02ff771 100644
--- a/stm32/aioc-fw/.cproject
+++ b/stm32/aioc-fw/.cproject
@@ -123,7 +123,7 @@
-
+
@@ -136,7 +136,7 @@
-
+
@@ -226,7 +226,14 @@
-
+
+
+
+
+
+
+
+
diff --git a/stm32/aioc-fw/Inc/stm32f3xx_hal_conf.h b/stm32/aioc-fw/Inc/stm32f3xx_hal_conf.h
index 2ccfd2b..e5a303c 100644
--- a/stm32/aioc-fw/Inc/stm32f3xx_hal_conf.h
+++ b/stm32/aioc-fw/Inc/stm32f3xx_hal_conf.h
@@ -53,7 +53,7 @@
/* #define HAL_I2C_MODULE_ENABLED */
/* #define HAL_I2S_MODULE_ENABLED */
/* #define HAL_IRDA_MODULE_ENABLED */
-/* #define HAL_IWDG_MODULE_ENABLED */
+#define HAL_IWDG_MODULE_ENABLED
/* #define HAL_OPAMP_MODULE_ENABLED */
/* #define HAL_PCD_MODULE_ENABLED */
#define HAL_PWR_MODULE_ENABLED
diff --git a/stm32/aioc-fw/Inc/tusb_config.h b/stm32/aioc-fw/Inc/tusb_config.h
index d333d6a..a1eb73f 100644
--- a/stm32/aioc-fw/Inc/tusb_config.h
+++ b/stm32/aioc-fw/Inc/tusb_config.h
@@ -98,6 +98,7 @@
#define CFG_TUD_AUDIO 1
#define CFG_TUD_CDC 1
#define CFG_TUD_HID 1
+#define CFG_TUD_DFU_RUNTIME 1
// CDC FIFO size of TX and RX
#define CFG_TUD_CDC_RX_BUFSIZE 128
diff --git a/stm32/aioc-fw/Src/main.c b/stm32/aioc-fw/Src/main.c
index e92fb97..6197d6f 100644
--- a/stm32/aioc-fw/Src/main.c
+++ b/stm32/aioc-fw/Src/main.c
@@ -6,6 +6,16 @@
#include
#include
+// from ST application note AN2606
+// Table 171: Bootloader device-dependent parameters
+#if defined(STM32F302xB) || defined(STM32F302xC) || \
+ defined(STM32F303xB) || defined(STM32F303xC) || \
+ defined(STM32F373xC)
+#define SYSTEM_MEMORY_BASE 0x1FFFD800
+#else
+#warning Live DFU reboot not supported on this MCU
+#endif
+
static void SystemClock_Config(void)
{
HAL_StatusTypeDef status;
@@ -63,6 +73,56 @@ static void SystemClock_Config(void)
HAL_RCC_MCOConfig(RCC_MCO1, RCC_MCO1SOURCE_PLLCLK_DIV2, RCC_MCODIV_1);
}
+static void SystemReset(void) {
+ uint32_t resetFlags = RCC->CSR;
+
+ /* Clear reset flags */
+ RCC->CSR |= RCC_CSR_RMVF;
+
+#if defined(SYSTEM_MEMORY_BASE)
+ if (resetFlags & RCC_CSR_IWDGRSTF) {
+ /* Reset cause was watchdog, which is used for rebooting into the bootloader.
+ Set stack pointer to *SYSTEM_MEMORY_BASE
+ and jump to *(SYSTEM_MEMORY_BASE + 4)
+ https://stackoverflow.com/a/42031657 */
+ asm volatile (
+ " msr msp, %[sp] \n"
+ " bx %[pc] \n"
+
+ :: [sp] "r" (*( (uint32_t*)(SYSTEM_MEMORY_BASE) )),
+ [pc] "r" (*( (uint32_t*)(SYSTEM_MEMORY_BASE + 4) ))
+ );
+ }
+#else
+ while(1)
+ ;
+#endif
+
+ /* Initialize HAL */
+ HAL_Init();
+
+ /* Enable Clock to SYSCFG */
+ __HAL_RCC_SYSCFG_CLK_ENABLE();
+
+ /* Enable SWO debug output */
+ GPIO_InitTypeDef GpioSWOInit = {
+ .Pin = GPIO_PIN_3,
+ .Mode = GPIO_MODE_AF_PP,
+ .Pull = GPIO_NOPULL,
+ .Speed = GPIO_SPEED_FREQ_LOW,
+ .Alternate = GPIO_AF0_TRACE
+ };
+ HAL_GPIO_Init(GPIOB, &GpioSWOInit);
+
+ /* Reset USB if necessary */
+ if (!(resetFlags & RCC_CSR_PORRSTF)) {
+ /* Since the USB Pullup is hardwired to the supply voltage,
+ * the host (re-)enumerates our USB device only during Power-On-Reset.
+ * For all other reset causes, do a manual USB reset. */
+ USB_Reset();
+ }
+}
+
int _write(int file, char *ptr, int len)
{
for (uint32_t i=0; iBRR = GPIO_PIN_12;
+
+ HAL_Delay(USB_RESET_DELAY);
+}
+
void USB_Init(void)
{
__HAL_REMAPINTERRUPT_USB_ENABLE();
diff --git a/stm32/aioc-fw/Src/usb.h b/stm32/aioc-fw/Src/usb.h
index 056b08f..31056d3 100644
--- a/stm32/aioc-fw/Src/usb.h
+++ b/stm32/aioc-fw/Src/usb.h
@@ -3,11 +3,14 @@
#include "usb_audio.h"
#include "usb_serial.h"
+#include "usb_dfu.h"
+#define USB_RESET_DELAY 100 /* milliseconds */
#define USB_SOF_TIMER TIM2
#define USB_SOF_TIMER_CNT TIM2->CNT
#define USB_SOF_TIMER_HZ 72000000UL
+void USB_Reset(void);
void USB_Init(void);
void USB_Task(void);
diff --git a/stm32/aioc-fw/Src/usb_descriptors.c b/stm32/aioc-fw/Src/usb_descriptors.c
index 8e2d903..c37604a 100644
--- a/stm32/aioc-fw/Src/usb_descriptors.c
+++ b/stm32/aioc-fw/Src/usb_descriptors.c
@@ -112,7 +112,8 @@ uint8_t const * tud_hid_descriptor_report_cb(uint8_t itf)
TUD_CONFIG_DESC_LEN + \
AIOC_AUDIO_DESC_LEN + \
AIOC_HID_DESC_LEN + \
- AIOC_CDC_DESC_LEN \
+ AIOC_CDC_DESC_LEN + \
+ AIOC_DFU_RT_DESC_LEN \
)
uint8_t const desc_fs_configuration[] = {
@@ -155,6 +156,16 @@ uint8_t const desc_fs_configuration[] = {
/* _epout */ EPNUM_CDC_0_OUT,
/* _epin */ EPNUM_CDC_0_IN,
/* _epsize */ CFG_TUD_CDC_EP_BUFSIZE
+ ),
+
+ AIOC_DFU_RT_DESCRIPTOR(
+ /* _itfnum */ ITF_NUM_DFU_RT,
+ /* _stridx */ STR_IDX_DFU_RT,
+ /* _attr */ DFU_ATTR_WILL_DETACH | \
+ DFU_ATTR_CAN_UPLOAD | \
+ DFU_ATTR_CAN_DOWNLOAD,
+ /* _timeout */ 255, /* not used if WILL_DETACH */
+ /* _xfer_size */ 2048 /* max size for stm32 dfu bootloader */
)
};
@@ -280,6 +291,10 @@ const uint16_t * tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
len = ascii_to_utf16(ptr, len, USB_STRING_HIDITF);
break;
+ case STR_IDX_DFU_RT:
+ len = ascii_to_utf16(ptr, len, USB_STRING_DFU_RT);
+ break;
+
default:
TU_ASSERT(0, NULL);
break;
diff --git a/stm32/aioc-fw/Src/usb_descriptors.h b/stm32/aioc-fw/Src/usb_descriptors.h
index d48ac98..394541f 100644
--- a/stm32/aioc-fw/Src/usb_descriptors.h
+++ b/stm32/aioc-fw/Src/usb_descriptors.h
@@ -9,6 +9,7 @@ enum USB_DESCRIPTORS_ITF {
ITF_NUM_HID, /* For CM108 compatibility make this interface #3 */
ITF_NUM_CDC_0,
ITF_NUM_CDC_0_DATA,
+ ITF_NUM_DFU_RT,
ITF_NUM_TOTAL
};
@@ -26,7 +27,8 @@ enum USB_STRING_IDX {
STR_IDX_AUDIOINCHAN,
STR_IDX_AUDIOOUTCHAN,
STR_IDX_HIDITF,
- STR_IDX_CDCITF
+ STR_IDX_CDCITF,
+ STR_IDX_DFU_RT
};
#define USB_VID 0x1209
@@ -44,6 +46,7 @@ enum USB_STRING_IDX {
#define USB_STRING_AUDIOOUTCHAN "AIOC Audio Out Channel"
#define USB_STRING_CDCITF "AIOC CDC"
#define USB_STRING_HIDITF "AIOC HID"
+#define USB_STRING_DFU_RT "AIOC DFU Runtime"
/* Endpoints */
#define EPNUM_AUDIO_IN 0x81
@@ -55,7 +58,6 @@ enum USB_STRING_IDX {
#define EPNUM_CDC_0_IN 0x84
#define EPNUM_CDC_0_NOTIF 0x85
-
/* Custom Audio Descriptor.
* Courtesy of https://github.com/hathach/tinyusb/issues/1249#issuecomment-1148727765 */
#define AUDIO_CTRL_ID_SPK_INPUT_STREAM 0x01
@@ -168,4 +170,8 @@ enum USB_STRING_IDX {
#define AIOC_CDC_DESCRIPTOR TUD_CDC_DESCRIPTOR
+#define AIOC_DFU_RT_DESC_LEN TUD_DFU_RT_DESC_LEN
+
+#define AIOC_DFU_RT_DESCRIPTOR TUD_DFU_RT_DESCRIPTOR
+
#endif /* USB_DESCRIPTORS_H_ */
diff --git a/stm32/aioc-fw/Src/usb_dfu.c b/stm32/aioc-fw/Src/usb_dfu.c
new file mode 100644
index 0000000..87dc9ca
--- /dev/null
+++ b/stm32/aioc-fw/Src/usb_dfu.c
@@ -0,0 +1,26 @@
+#include "usb_dfu.h"
+#include "stm32f3xx_hal.h"
+#include "tusb.h"
+#include "usb.h"
+
+// Invoked on DFU_DETACH request to reboot to the bootloader
+void tud_dfu_runtime_reboot_to_dfu_cb(void)
+{
+ /* Reset USB and force reset via watchdog timer. */
+ USB_Reset();
+
+ IWDG_HandleTypeDef IWDGHandle = {
+ .Instance = IWDG,
+ .Init = {
+ .Prescaler = IWDG_PRESCALER_4,
+ .Reload = 128,
+ .Window = 0x0FFF
+ }
+ };
+
+ HAL_IWDG_Init(&IWDGHandle);
+
+ while(1) {
+ /* Wait for Reset */
+ }
+}
diff --git a/stm32/aioc-fw/Src/usb_dfu.h b/stm32/aioc-fw/Src/usb_dfu.h
new file mode 100644
index 0000000..6dd64b4
--- /dev/null
+++ b/stm32/aioc-fw/Src/usb_dfu.h
@@ -0,0 +1,4 @@
+#ifndef USB_DFU_H_
+#define USB_DFU_H_
+
+#endif /* USB_DFU_H_ */
diff --git a/stm32/aioc-fw/makefile.targets b/stm32/aioc-fw/makefile.targets
new file mode 100644
index 0000000..ba47e9c
--- /dev/null
+++ b/stm32/aioc-fw/makefile.targets
@@ -0,0 +1,13 @@
+dfu-suffix: $(OBJCOPY_BIN)
+ifneq ("$(wildcard /usr/bin/dfu-suffix)","")
+ dfu-suffix -c $(FILENAME) || dfu-suffix -a $(FILENAME) -p $(PID) -v $(VID) -d $(DID)
+else
+ @echo "Skipping DFU suffix generation, because dfu-suffix tool was not found"
+endif
+
+dfu-util: dfu-suffix
+ifneq ("$(wildcard /usr/bin/dfu-util)","")
+ dfu-util -d $(VID):$(PID) -a 0 -s 0x08000000:leave -D $(FILENAME)
+else
+ @echo "Skipping DFU programming, because dfu-util tool was not found"
+endif