cancel
Showing results for 
Search instead for 
Did you mean: 

stm32f446vet

pingpong999
Associate

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

 

5 REPLIES 5
Sarra.S
ST Employee

Hello @pingpong999

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

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

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

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

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

 

> 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