STM32F303ZE -- Not receiving SET_ADDRESS after responding to GET_DESCRIPTOR.
Problem
I'm having an issue with my USB peripheral in the STM32F303ZE. Right now I'm capable of receiving the first request from the host after reset, which is a GET_DESCRIPTOR request. I populate the TX buffer and set the EP0R register to VALID for TX. I then get interrupted for an IN request, meaning the host ACKed my TX data (which I assume means the data was transmitted successfully) and then I receive an OUT status to finish the control transfer. And then I receive a reset and do this all over again two more times, resulting in the device failing to enumerate.
What confuses me is that, from experience programming USB on a different MCU, I know I should be receiving a reset partway through transferring my device descriptor, yet the entire request goes through and then I receive the reset afterwards. While it may be possible that the host is letting my transfer complete, I still don't receive a SET_ADDRESS setup packet afterwards. As I said above, it just repeats over and over. My hope here is to get help in receiving the SET_ADDRESS next.
Clocks
I've already verified the clocks are correct. I'm bypassing an 8MHz clock as HSE and multiplying it by 6 with the PLL to reach the required 48MHz for the USB peripheral. Also, I wouldn't receive the GET_DESCRIPTOR if the peripheral wasn't being clocked. I already struggled with trying to use an external oscillator that wasn't actually on the board... For reference though, this is my configuration
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_BYPASS;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL6;
RCC_OscInitStruct.PLL.PREDIV = RCC_PREDIV_DIV1;
HAL_RCC_OscConfig(&RCC_OscInitStruct)
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1)
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USB|RCC_PERIPHCLK_USART3
|RCC_PERIPHCLK_ADC12|RCC_PERIPHCLK_TIM34;
PeriphClkInit.Usart3ClockSelection = RCC_USART3CLKSOURCE_HSI;
PeriphClkInit.Adc12ClockSelection = RCC_ADC12PLLCLK_DIV1;
PeriphClkInit.USBClockSelection = RCC_USBCLKSOURCE_PLL;
PeriphClkInit.Tim34ClockSelection = RCC_TIM34CLK_PLLCLK;
HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit)USB Code:
Bear with me, the code is in a very prototypish stage right now
Declarations
USB_TypeDef * USBz; /* USB Address Handle */
typedef struct __attribute__((packed))
{
__IO uint16_t ADDR_TX;
__IO uint16_t COUNT_TX;
__IO uint16_t ADDR_RX;
__IO uint16_t COUNT_RX;
} BTableLayout;
volatile BTableLayout *my_btable;
volatile uint8_t buffer[64];
union Device{
DeviceDescriptor descriptor;
uint8_t data[18];
} device;
uint8_t address = 0;Initialization
void myusb_Initialize(void)
{
//Initialize Descriptors
DescriptorInitialization();
//Map USBz to registers
USBz = USB;
my_btable = (BTableLayout*)0x40006000;
//Enable clocks
__HAL_RCC_USB_CLK_ENABLE();
//Initialize interrupts + remapping
__HAL_REMAPINTERRUPT_USB_ENABLE();
HAL_NVIC_SetPriority(USB_HP_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(USB_HP_IRQn);
HAL_NVIC_SetPriority(USB_LP_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(USB_LP_IRQn);
HAL_NVIC_SetPriority(USBWakeUp_RMP_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(USBWakeUp_RMP_IRQn);
//Configure USB GPIO
__HAL_RCC_GPIOG_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF14_USB;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_6;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOG, GPIO_PIN_6, GPIO_PIN_RESET);
//Start USB peripheral
USBz->CNTR = 1; //Start transceiver
for (int i = 0; i < 1000; i++) //Delay according to datasheet
{
__asm volatile("nop");
}
//De-assert reset
USBz->CNTR = 0;
//Clear pending interrupts
USBz->ISTR = 0U;
//Enable these USB Interrupts
USBz->CNTR |= USB_CNTR_RESETM | USB_CNTR_CTRM | USB_CNTR_WKUPM | USB_CNTR_SUSPM | USB_CNTR_ESOFM;
//Enable pull up to start enumeration
HAL_GPIO_WritePin(GPIOG, GPIO_PIN_6, GPIO_PIN_SET);
}
void DescriptorInitialization(void)
{
//Just device descriptor until I reach further requests
device.descriptor.bLength = 18;
device.descriptor.bDescriptorType = 0x01;
device.descriptor.bcdUSB = 0x0110;
device.descriptor.bDeviceClass = 0x00;
device.descriptor.bDeviceSubClass = 0x00;
device.descriptor.bDeviceProtocol = 0x00;
device.descriptor.bMaxPacketSize0 = 64;
device.descriptor.idVendor = 0x03ED;
device.descriptor.idProduct = 0x2FF4;
device.descriptor.bcdDevice = 0x0100;
device.descriptor.iManufacturer = 0x00;
device.descriptor.iProduct = 0x00;
device.descriptor.iSerialNumber = 0x00;
device.descriptor.bNumConfigurations = 1;
}Read/Write Functions
void ReadEndpoint(uint8_t endpoint, uint8_t num_bytes)
{
//Get offset to endpoint n RX buffer
volatile uint8_t* location = (uint8_t*)(0x40006000 + ((endpoint * 8) + 4));
//Point to RX buffer
location = ((uint8_t*)0x40006000 + (*location));
for (int i = 0; i < num_bytes; i++)
{
buffer[i] = ((uint8_t*)location)[i];
}
}
void WriteEndpoint(uint8_t endpoint, uint8_t* data_buffer, uint8_t num_bytes)
{
//Get offset to endpoint n TX buffer
volatile uint8_t* location = (uint8_t*)(0x40006000 + (endpoint*8));
//Point to TX buffer
location = ((uint8_t*)0x40006000 + (*location));
for (int i = 0; i < num_bytes; i++)
{
location[i] = data_buffer[i];
}
//Set STAT_TX to VALID. Mask to avoid toggling the toggle bits.
switch(endpoint)
{
case 0:
USBz->EP0R = (1 << 4) | (USBz->EP0R & 0x8F9F);
break;
case 1:
USBz->EP1R = (1 << 4) | (USBz->EP1R & 0x8F9F);
break;
}
}CONTINUATION OF CODE IN COMMENTS
