Skip to main content
Visitor II
December 30, 2024
Question

stm32f446vet

  • December 30, 2024
  • 3 replies
  • 1271 views

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();
}

 

    This topic has been closed for replies.

    3 replies

    ST Employee
    December 30, 2024

    Hello @pingpong999

    Could you verify that the PLLSAI is locking by checking the PLLSAIRDY flag?

    Visitor II
    December 30, 2024

    thanks for the reply. 

    i just ran this block and can confirm it locks which is great. im a little stumped on why im not able to register usb communication. should my d plus line be high? both d- and d+ are low

    
    struct PLLDividers {
     uint32_t M;
     uint32_t N;
     uint32_t P;
     uint32_t Q;
    };
    
    const PLLDividers mainPLL {4, 180, 2, 7};
    const PLLDividers saiPLL {6, 144, 4, 0};
    
    void InitClocks() {
     RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN;
     [[maybe_unused]] 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;
     while ((RCC->CR & RCC_CR_PLLSAIRDY) == 0); // Check pllsairdy here
    
     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();
    }
    
    
    int main() {
     RCC->CR |= RCC_CR_PLLSAION;
     while ((RCC->CR & RCC_CR_PLLSAIRDY) == 0);
     printf("PLLSAI locked and ready\n");
     while (1);
    }
    Super User
    December 30, 2024

    Observe the USB registers in debugger, whether they do have the expected values.

    > USB_OTG_FS->GCCFG |= USB_OTG_GCCFG_VBDEN; // Enable HW VBUS sensing

    Do you have VBUS-derived voltage connected to given pin? Is GOTGCTL.BSVLD set?

    JW

    Visitor II
    December 31, 2024

    this is my usb register dump, GOTGCTL = 0x03010000 does not have bit 19 set, so BSVLD is not set which makes me think its a hardware issue

    GOTGCTL = 0x03010000
     GOTGINT = 0x00100000
     GAHBCFG = 0x00000001
     GUSBCFG = 0x40001440
     GRSTCTL = 0x80000000
     GINTSTS = 0x04008020
     GINTMSK = 0xC00C3814
     GRXFSIZ = 0x00000080
     DIEPTXF0 = 0x00400080
     DIEPTXF1 = 0x004000C0
     DIEPTXF2 = 0x00400100
     GCCFG = 0x0021FFF0
     CID = 0x00002000
     DCFG = 0x08200003
     DCTL = 0x00000000
     DSTS = 0x0007FF06
     DIEPMSK = 0x00000000
     DOEPMSK = 0x00000000
     DAINT = 0x00000000
     DAINTMSK = 0x00000000

     

    Super User
    December 31, 2024

    > BSVLD is not set

    Do you have VBUS-derived voltage connected to given pin?

    You can override VBUS detection by clearing GCCFG.VBDEN and setting GOTGCTL.VBVALOEN and GOTGCTL.BVALOVAL.

    JW