Question
stm32f446vet
im struggling to get usb fs working on a custom stm32f446vet dev board. im slightly aware that this may be an explored problem but in need of some guidance.
i suspect the PLLSAI never locks.
some init code for context
void USB::Init(bool softReset)
{
volatile uint32_t count = 0;
if (!softReset) {
GpioPin::Init(GPIOA, 9, GpioPin::Type::Input); // PA9: USB_OTG_HS_VBUS
GpioPin::Init(GPIOA, 11, GpioPin::Type::AlternateFunction, 10); // PA11: USB_OTG_HS_DM
GpioPin::Init(GPIOA, 12, GpioPin::Type::AlternateFunction, 10); // PA12: USB_OTG_HS_DP
RCC->DCKCFGR2 |= RCC_DCKCFGR2_CK48MSEL; // 0 = PLLQ Clock; 1 = PLLSAI_P
RCC->AHB2ENR |= RCC_AHB2ENR_OTGFSEN; // USB OTG FS clock enable
RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN; // Enable system configuration clock: used to manage external interrupt line connection to GPIOs
NVIC_SetPriority(OTG_FS_IRQn, 2);
NVIC_EnableIRQ(OTG_FS_IRQn);
}
USB_OTG_FS->GCCFG |= USB_OTG_GCCFG_PWRDWN; // Activate the transceiver in transmission/reception. When reset, the transceiver is kept in power-down. 0 = USB FS transceiver disabled; 1 = USB FS transceiver enabled
USB_OTG_FS->GUSBCFG |= USB_OTG_GUSBCFG_FDMOD; // Force USB device mode
DelayMS(50);
// Clear all transmit FIFO address and data lengths - these will be set to correct values below for endpoints 0,1 and 2
for (uint8_t i = 0; i < 15; i++) {
USB_OTG_FS->DIEPTXF[i] = 0;
}
USB_OTG_FS->GCCFG |= USB_OTG_GCCFG_VBDEN; // Enable HW VBUS sensing
USBx_DEVICE->DCFG |= USB_OTG_DCFG_DSPD; // 11: Full speed using internal FS PHY
USB_OTG_FS->GRSTCTL |= USB_OTG_GRSTCTL_TXFNUM_4; // Select buffers to flush. 10000: Flush all the transmit FIFOs in device or host mode
USB_OTG_FS->GRSTCTL |= USB_OTG_GRSTCTL_TXFFLSH; // Flush the TX buffers
while (++count < 100000 && (USB_OTG_FS->GRSTCTL & USB_OTG_GRSTCTL_TXFFLSH));
USB_OTG_FS->GRSTCTL = USB_OTG_GRSTCTL_RXFFLSH; // Flush the RX buffers
count = 0;
while (++count < 100000 && (USB_OTG_FS->GRSTCTL & USB_OTG_GRSTCTL_RXFFLSH));
USB_OTG_FS->GINTSTS = 0xBFFFFFFF; // Clear pending interrupts (except SRQINT Session request/new session detected)
// Enable interrupts
USB_OTG_FS->GINTMSK = 0; // Disable all interrupts
USB_OTG_FS->GINTMSK |= USB_OTG_GINTMSK_RXFLVLM | USB_OTG_GINTMSK_USBSUSPM | // Receive FIFO non-empty mask; USB suspend
USB_OTG_GINTMSK_USBRST | USB_OTG_GINTMSK_ENUMDNEM | // USB reset; Enumeration done
USB_OTG_GINTMSK_IEPINT | USB_OTG_GINTMSK_OEPINT | USB_OTG_GINTMSK_WUIM | // IN endpoint; OUT endpoint; Resume/remote wakeup detected
USB_OTG_GINTMSK_SRQIM | USB_OTG_GINTMSK_OTGINT; // Session request/new session detected; OTG interrupt
// NB - FIFO Sizes are in words NOT bytes. There is a total size of 320 (320x4 = 1280 bytes) available which is divided up thus:
// FIFO Start Size
// RX 0 128
// EP0 TX 128 64
// EP1 TX 192 64
// EP2 TX 256 64
USB_OTG_FS->GRXFSIZ = 128; // Rx FIFO depth
// Endpoint 0 Transmit FIFO size/address (as in device mode - this is also used as the non-periodic transmit FIFO size in host mode)
USB_OTG_FS->DIEPTXF0_HNPTXFSIZ = (64 << USB_OTG_TX0FD_Pos) | // IN Endpoint 0 Tx FIFO depth
(128 << USB_OTG_TX0FSA_Pos); // IN Endpoint 0 FIFO transmit RAM start address - this is offset from the RX FIFO (set above to 128)
// Endpoint 1 FIFO size/address (address is offset from EP0 address+size above)
USB_OTG_FS->DIEPTXF[0] = (64 << USB_OTG_DIEPTXF_INEPTXFD_Pos) | // IN endpoint 1 Tx FIFO depth
(192 << USB_OTG_DIEPTXF_INEPTXSA_Pos); // IN endpoint 1 FIFO transmit RAM start address
// Endpoint 2 FIFO size/address (address is offset from EP1 address+size above)
USB_OTG_FS->DIEPTXF[1] = (64 << USB_OTG_DIEPTXF_INEPTXFD_Pos) | // IN endpoint 2 Tx FIFO depth
(256 << USB_OTG_DIEPTXF_INEPTXSA_Pos); // IN endpoint 2 FIFO transmit RAM start address
USBx_DEVICE->DCTL &= ~USB_OTG_DCTL_SDIS; // Activate USB
USB_OTG_FS->GAHBCFG |= USB_OTG_GAHBCFG_GINT; // Activate USB Interrupts
transmitting = false;
}
struct PLLDividers {
uint32_t M;
uint32_t N;
uint32_t P;
uint32_t Q;
};
const PLLDividers mainPLL {4, 180, 2, 7}; // Clock: 8MHz / 4(M) * 168(N) / 2(P) = 180MHz
const PLLDividers saiPLL {6, 144, 4, 0}; // USB: 8MHz / 6(M) * 144(N) / 4(P) = 48MHz
void InitClocks()
{
RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN;
volatile uint32_t dummy = RCC->APB2ENR & RCC_APB2ENR_SYSCFGEN;
RCC->APB1ENR |= RCC_APB1ENR_PWREN;
PWR->CR |= PWR_CR_VOS_0;
SCB->CPACR |= ((3 << 10 * 2) | (3 << 11 * 2));
RCC->CR |= RCC_CR_HSEON;
while ((RCC->CR & RCC_CR_HSERDY) == 0);
RCC->PLLCFGR = (mainPLL.M << RCC_PLLCFGR_PLLM_Pos) |
(mainPLL.N << RCC_PLLCFGR_PLLN_Pos) |
(((mainPLL.P >> 1) - 1) << RCC_PLLCFGR_PLLP_Pos) |
(mainPLL.Q << RCC_PLLCFGR_PLLQ_Pos) |
RCC_PLLCFGR_PLLSRC_HSE;
RCC->CFGR |= RCC_CFGR_HPRE_DIV1 | RCC_CFGR_PPRE1_DIV4 | RCC_CFGR_PPRE2_DIV2;
RCC->CR |= RCC_CR_PLLON;
while ((RCC->CR & RCC_CR_PLLRDY) == 0);
RCC->PLLSAICFGR = (saiPLL.M << RCC_PLLSAICFGR_PLLSAIM_Pos) |
(saiPLL.N << RCC_PLLSAICFGR_PLLSAIN_Pos) |
(((saiPLL.P >> 1) - 1) << RCC_PLLSAICFGR_PLLSAIP_Pos);
RCC->CR |= RCC_CR_PLLSAION;
FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN | FLASH_ACR_DCEN | FLASH_ACR_LATENCY_5WS;
RCC->CFGR &= ~RCC_CFGR_SW;
RCC->CFGR |= RCC_CFGR_SW_PLL;
while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL);
FLASH->ACR |= FLASH_ACR_ICEN | FLASH_ACR_DCEN | FLASH_ACR_PRFTEN;
SystemCoreClockUpdate();
}
