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 @@ - + - + + + + + + + + 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