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