techmannih/nema34-mounted-stepper-controller
A 48 V USB‑C PD 3.1 EPR NEMA‑34 stepper controller PCB combining STM32/TMC5160 control, external MOSFET motor bridges, protected power and regenerative braking, USB data, telemetry, diagnostics, status LEDs, and buzzer alarms.
- Version
- 0.3.92
- License
- unset
- Stars
- 1
firmware/target/usb_suspend.cpp
#include <Arduino.h>
#include "usbd_def.h"
#include "stm32g0xx_ll_rcc.h"
#include "usb_suspend.h"
extern "C" PCD_HandleTypeDef g_hpcd;
static RTC_HandleTypeDef wakeTimer;
void initializeSuspendTimer() {
// IWDG already enabled LSI. The RTC wake timer runs from that same oscillator,
// giving five wake intervals per watchdog period regardless of LSI tolerance.
__HAL_RCC_PWR_CLK_ENABLE();
HAL_PWR_EnableBkUpAccess();
__HAL_RCC_RTC_CONFIG(RCC_RTCCLKSOURCE_LSI);
__HAL_RCC_RTC_ENABLE();
__HAL_RCC_RTCAPB_CLK_ENABLE();
wakeTimer.Instance = RTC;
wakeTimer.Init.HourFormat = RTC_HOURFORMAT_24;
wakeTimer.Init.AsynchPrediv = 127;
wakeTimer.Init.SynchPrediv = 249;
wakeTimer.Init.OutPut = RTC_OUTPUT_DISABLE;
wakeTimer.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
wakeTimer.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
if (HAL_RTC_Init(&wakeTimer) != HAL_OK) Error_Handler();
HAL_NVIC_SetPriority(RTC_TAMP_IRQn, 2, 0);
HAL_NVIC_EnableIRQ(RTC_TAMP_IRQn);
}
extern "C" void RTC_TAMP_IRQHandler() {
HAL_RTCEx_WakeUpTimerIRQHandler(&wakeTimer);
// The main loop, never this interrupt, must service the independent watchdog.
}
bool usbIsSuspended() {
const auto *device = static_cast<volatile USBD_HandleTypeDef *>(g_hpcd.pData);
return device && device->dev_state == USBD_STATE_SUSPENDED;
}
static void restoreClocks() {
// STOP retains PLL configuration but wakes on HSI16. Restore the pinned
// generic G0B1 clock (64 MHz PLL + HSI48) before pending USB IRQs execute.
LL_RCC_HSI48_Enable();
LL_RCC_PLL_Enable();
uint32_t remaining = 200000;
while (!LL_RCC_HSI48_IsReady() || !LL_RCC_PLL_IsReady()) {
if (!--remaining) NVIC_SystemReset();
}
LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL);
remaining = 200000;
while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL) {
if (!--remaining) NVIC_SystemReset();
}
}
void sleepWhileUsbSuspended() {
// RTC wake also lets main detect cable removal and reload the 250 ms IWDG.
if (HAL_RTCEx_SetWakeUpTimer_IT(&wakeTimer, 99, RTC_WAKEUPCLOCK_RTCCLK_DIV16) != HAL_OK)
Error_Handler();
__HAL_USB_WAKEUP_EXTI_ENABLE_IT();
HAL_SuspendTick();
__disable_irq();
// Atomic recheck avoids sleeping after a resume/reset already handled by USB.
if (usbIsSuspended() && (USB->CNTR & USB_CNTR_SUSPRDY)) {
__DSB();
HAL_PWR_EnterSTOPMode(PWR_MAINREGULATOR_ON, PWR_STOPENTRY_WFI);
restoreClocks();
}
__enable_irq();
HAL_ResumeTick();
if (HAL_RTCEx_DeactivateWakeUpTimer(&wakeTimer) != HAL_OK) Error_Handler();
}