1
votes

The STM32F723IEK6 Discovery board has a full speed USB interface. I am trying in vain to initialize it. The reset signal is never received from the host and the appropriate interrupt flag is not set.

The FS interface is OTG. It is supposed to detect VBUS voltage and the state of the ID pin to determine if it is connected as host or as device. In the device mode VBUS should be provided by the host and the ID pin should be disconnected and pulled HIGH. When the device detects a connection, it should pull the DP pin to indicate connection to the host. Then the host sends the RESET signal by pulling data lines low. This is the theory.

It appears that the board does not pull high the DP line. In the default OTG configuration (as in the program below) with VBUS detection enabled, only CIDSCHG (ID change), SRQINT (session), and SOF bits are ever set in the GINTSTS register. The CMOD bit is zero, indicating the device mode. The ID line seems to be low, even when the cable is not connected.

I configure the appropriate pins (A9, A10, A11, A12) in the AF 10 mode (OTG FS). However, this may be unnecessary, since the FS PHY seems to be connected directly to the pins, bypassing the GPIO multiplexer (not sure).

I have tried forcing the device mode and disabling VBUS detection, but this caused no effect, as well as pulling up the ID line from GPIO.

I have the same code running on an STM32F4 board before and had no such problems.

I would like to understand why connection detection does not work.

The code is below, sorry for being wordy, it has the clock, GPIO, and USB initialization code, some auxiliary functions are omitted.

STM32F72x reference manual (15MB!) http://www.st.com/resource/en/reference_manual/dm00305990.pdf

Datasheet http://www.st.com/resource/en/datasheet/DM00330506.pdf

Board manual http://www.st.com/resource/en/user_manual/dm00342318.pdf

#include "stm32f7xx.h"

#define PLL_M 25
#define PLL_N 336
#define PLL_P 0
#define PLL_Q 7
#define SYS_FREQ 168000000

void rcc_config(void)
{
    RCC->APB1ENR |= RCC_APB1ENR_PWREN;
    PWR->CR1 = (PWR->CR1 & ~PWR_CR1_VOS_Msk)
            | PWR_CR1_VOS_1;
    RCC->CR |= RCC_CR_HSEON;
    while ((RCC->CR & RCC_CR_HSERDY) == 0);
    RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (PLL_P << 16) | RCC_PLLCFGR_PLLSRC_HSE | (PLL_Q << 24);
    RCC->CR |= RCC_CR_PLLON;
    RCC->CFGR = (RCC->CFGR & ~(RCC_CFGR_HPRE_Msk | RCC_CFGR_PPRE1_Msk | RCC_CFGR_PPRE2_Msk))
            | RCC_CFGR_HPRE_DIV1
            | RCC_CFGR_PPRE2_DIV2
            | RCC_CFGR_PPRE1_DIV4;
    FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ARTEN | FLASH_ACR_LATENCY_5WS;
    while ((RCC->CR & RCC_CR_PLLRDY) == 0);
    while ((PWR->CSR1 & PWR_CSR1_VOSRDY) == 0);
    RCC->CFGR &= RCC_CFGR_SW;
    RCC->CFGR |= RCC_CFGR_SW_PLL;
    while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL);
}

#define GPIO_OTYPE_PP 0
#define GPIO_OTYPE_OD 1
#define GPIO_PULLUP   1

void gpio_config_mode(GPIO_TypeDef* gpio, unsigned pin, unsigned mode)
{
    gpio->MODER = (gpio->MODER & ~(3u << (2 * pin))) | (mode << (2 * pin));
}
void gpio_config_in(GPIO_TypeDef* gpio, unsigned pin)
{
    gpio_config_mode(gpio, pin, 0);
}
void gpio_config_out(GPIO_TypeDef* gpio, unsigned pin, unsigned otype, unsigned ospeed)
{
    gpio_config_mode(gpio, pin, 1);
    gpio->OTYPER  = (gpio->OTYPER  & ~(1u << (1 * pin))) | (otype  << (1 * pin));
    gpio->OSPEEDR = (gpio->OSPEEDR & ~(3u << (2 * pin))) | (ospeed << (2 * pin));
}
void gpio_config_af(GPIO_TypeDef* gpio, unsigned pin, unsigned af)
{
    gpio_config_mode(gpio, pin, 2);
    unsigned pin_group = pin >> 3;
    unsigned pin_offset = pin & 7;
    gpio->AFR[pin_group] = (gpio->AFR[pin_group] & ~(0xf << (pin_offset * 4)))
            | (af << (pin_offset * 4));
}
void gpio_config_pullup(GPIO_TypeDef* gpio, unsigned pin, unsigned pupd)
{
    gpio->PUPDR = (gpio->PUPDR   & ~(3u << (2 * pin))) | (pupd   << (2 * pin));
}

USB_OTG_GlobalTypeDef *usb = USB_OTG_FS;
USB_OTG_DeviceTypeDef *usb_dev = (USB_OTG_DeviceTypeDef *)(USB_OTG_FS_PERIPH_BASE + USB_OTG_DEVICE_BASE);

void usb_config(void)
{
    /* The application must program this register before starting any transactions
     * on either the AHB or the USB. Do not make changes to this register after
     * the initial programming. */
    usb->GUSBCFG |= USB_OTG_GUSBCFG_PHYSEL; // TODO: no effect for F7, read-only bit
//  usb->GUSBCFG |= USB_OTG_GUSBCFG_FDMOD;
    /* After setting the force bit, the application must wait at least * 25 ms
     * before the change takes effect. */
    delay_ms(25);

    // USB core reset
    while ((usb->GRSTCTL & USB_OTG_GRSTCTL_AHBIDL) == 0);
    usb->GRSTCTL |= USB_OTG_GRSTCTL_CSRST;
    while ((usb->GRSTCTL & USB_OTG_GRSTCTL_CSRST) != 0);
    delay_us(1); // actually, 3 PHY clocks

    usb_dev->DCFG = USB_OTG_DCFG_DSPD_0 | USB_OTG_DCFG_DSPD_1; // full speed
//  usb->GAHBCFG = 0;
//  usb->PCGCTL = 0;
    usb->GCCFG |= USB_OTG_GCCFG_VBDEN; // VBUS detection
    usb->GCCFG |= USB_OTG_GCCFG_PWRDWN; // enable PHY

/// usb->GINTSTS= 0xFFFFFFFF;
//  usb->GINTMSK = 0;
//  usb->GINTSTS = 0xFFFFFFFF;
//  usb->GAHBCFG |= USB_OTG_GAHBCFG_GINT;
}

void usb_poll(void)
{
    uint32_t intsts = usb->GINTSTS;
    if (intsts & USB_OTG_GINTSTS_USBRST)
        usb->GINTSTS = USB_OTG_GINTSTS_USBRST;
    if (intsts & USB_OTG_GINTSTS_RSTDET)
        usb->GINTSTS = USB_OTG_GINTSTS_RSTDET;
    if (intsts & USB_OTG_GINTSTS_ENUMDNE)
        usb->GINTSTS = USB_OTG_GINTSTS_ENUMDNE;
    if (intsts & USB_OTG_GINTSTS_CIDSCHG)
        usb->GINTSTS = USB_OTG_GINTSTS_CIDSCHG;
    if (intsts & USB_OTG_GINTSTS_SRQINT)
        usb->GINTSTS = USB_OTG_GINTSTS_SRQINT;
}

#define LED_PIN 5
#define USB_AF 10

int main()
{
    rcc_config();

    SysTick->LOAD = 0xffffffu;
    SysTick->VAL = 0;
    SysTick->CTRL = 5;

    RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
    gpio_config_out(GPIOA, LED_PIN, GPIO_OTYPE_PP, 0);
    gpio_config_af(GPIOA,  9, USB_AF); // VBUS_DET
    gpio_config_af(GPIOA, 10, USB_AF); // ID
    gpio_config_af(GPIOA, 11, USB_AF); // DM
    gpio_config_af(GPIOA, 12, USB_AF); // DP

    RCC->AHB2ENR |= RCC_AHB2ENR_OTGFSEN;
    usb_config();
    while (1)
        usb_poll();
}
1

1 Answers

1
votes

Of course.

OTG_FS_DCTL register:

Bit 1

SDIS:

Soft disconnect The application uses this bit to signal the USB OTG core to perform a soft disconnect. As long as this bit is set, the host does not see that the device is connected, and the device does not receive signals on the USB. The core stays in the disconnected state until the application clears this bit. 0: Normal operation. When this bit is cleared after a soft disconnect, the core generates a device connect event to the USB host. When the device is reconnected, the USB host restarts device enumeration. 1: The core generates a device disconnect event to the USB host.

From the STM32F411 manual:

Reset value: 0x0000 0000

From the STM32F723 manual:

Reset value: 0x0000 0002

Unless the reset value is modified by the application, the STM32F7 USB block starts in the "soft disconnect" state, while STM32F4 attempts to connect immediately, upon detection of VBUS. The documentation (e.g. section 32.6.2 Peripheral states) does not mention this fact at all.

In my case, clearing the SDIS bit enabled successful connection handshake.