USBX on STM32H563 - Unaligned Access Confusion
I've been on an adventure trying to get my first CubeMX/STM32 project off the ground. Here's as much context as I can give for my debugging process, and hopefully someone can spot what I'm missing.
Dev Board: Nucleo-STM32H563ZIT-144 (Arm M33 Core)
IDE: VSCode running STM32 V3 (Pre-Release) Toolchain (not using Clang -> using VSCode C/C++ Language Server for Intellisense) on Windows 11
Build Tooling: CMake and GCC with code generated from CubeMX using FW/HAL v1.5.0
Middlewares Used: ThreadX, NetXDuo, USBX
Initial Debugging:
First off, the rest of the code base has been working fine, the general ThreadX Application, Netx stack/App, and any additional code I have added hasn't generated unaligned access faults. I have not been using the MPU, and have explicitly disabled it in the entrypoint using HAL_MPU_Disable() as well as inside Cube MX
main.c
int main(void)
{
/* USER CODE BEGIN 1 */
/* Disable MPU */
HAL_MPU_Disable();
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* Disable MPU */
HAL_MPU_Disable();
/* Setup EEPROM Emulation */
EE_InitStorage();
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* GTZC initialisation */
MX_GTZC_Init();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPDMA1_Init();
MX_GPIO_Init();
MX_ICACHE_Init();
MX_SPI1_Init();
MX_FLASH_Init();
MX_UCPD1_Init();
MX_RNG_Init();
MX_HASH_Init();
/* Call PreOsInit function */
USBPD_PreInitOs();
/* USER CODE BEGIN 2 */
// NOTE: Don't call MX_USB_PCD_Init() here, as it is called by the ThreadX application
// NOTE: The ThreadX Application calls MX_ETH_Init() to initialize the Ethernet interface
/* Configure DMA for VCP UART Receive*/
/* USER CODE END 2 */
MX_ThreadX_Init();
/* USER CODE BEGIN WHILE */
/* We should never get here as control is now taken by the scheduler */
while (1) {
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}I followed the resolutions in this post and this post , but even with the MPU disabled, USBX was still causing an UNALIGNED hard fault when trying to build the descriptors due to the pEpDesc->wMaxPacketSize being only a uint_16t. I then added a post-generation codemod to update the macros to work with 32Bit-Aligned memory as well as telling the compiler to "unpack" some of the structs. Below is the code I ended up with for the USBX stack. This code WORKED and did not generate any UNALIGNED hard faults. However, I was weary of using unpacked structs in the case that they were bitwise serialized from memory in a lower-level function somewhere in the stack.
First Attempt: Code worked with a simple CDC ACM, non-composite device.
ux_device_descriptors.h
typedef struct
{
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t bcdUSB;
uint8_t bDeviceClass;
uint8_t bDeviceSubClass;
uint8_t bDeviceProtocol;
uint8_t bMaxPacketSize;
uint16_t idVendor;
uint16_t idProduct;
uint16_t bcdDevice;
uint8_t iManufacturer;
uint8_t iProduct;
uint8_t iSerialNumber;
uint8_t bNumConfigurations;
} USBD_DeviceDescTypedef; // was } __PACKED USBD_DeviceDescTypedef;
// ...
typedef struct
{
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bInterfaceNumber;
uint8_t bAlternateSetting;
uint8_t bNumEndpoints;
uint8_t bInterfaceClass;
uint8_t bInterfaceSubClass;
uint8_t bInterfaceProtocol;
uint8_t iInterface;
} USBD_IfDescTypedef; // was } __PACKED USBD_IfDescTypedef;
// ...
typedef struct
{
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bEndpointAddress;
uint8_t bmAttributes;
uint16_t wMaxPacketSize;
uint8_t bInterval;
} USBD_EpDescTypedef; // was } __PACKED USBD_EpDescTypedef;
// ...
/* USER CODE BEGIN Private_macro */
#define __USBD_FRAMEWORK_SET_EP_MEMSAFE(epadd, eptype, epsize, HSinterval, FSinterval) do { \
USBD_EpDescTypedef localEpDesc; \
memset((void *)&localEpDesc, 0, sizeof(USBD_EpDescTypedef)); \
\
/* Append Endpoint descriptor to Configuration descriptor */ \
pEpDesc = ((USBD_EpDescTypedef*)((uint32_t)pConf + *Sze)); \
localEpDesc.bLength = (uint8_t)sizeof(USBD_EpDescTypedef); \
localEpDesc.bDescriptorType = USB_DESC_TYPE_ENDPOINT; \
localEpDesc.bEndpointAddress = (epadd); \
localEpDesc.wMaxPacketSize = (epsize); \
localEpDesc.bmAttributes = (eptype); \
if (pdev->Speed == USBD_HIGH_SPEED) \
{ \
localEpDesc.bInterval = (HSinterval); \
} \
else \
{ \
localEpDesc.bInterval = (FSinterval); \
} \
* Sze += (uint32_t)sizeof(USBD_EpDescTypedef); \
\
memcpy((void *)pEpDesc, (void *)&localEpDesc, sizeof(USBD_EpDescTypedef)); \
} while (0)
/* USER CODE END Private_macro */ux_device_cdc_acm.c
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file ux_device_cdc_acm.c
* @author MCD Application Team
* @brief USBX Device applicative file
******************************************************************************
* @attention
*
* Copyright (c) 2025 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "ux_device_cdc_acm.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "main.h"
#include "string.h"
#include "app_threadx.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
__aligned(4) UX_SLAVE_CLASS_CDC_ACM* cdc_acm;
__IO ITStatus UartUSBReady = RESET;
UX_SLAVE_CLASS_CDC_ACM_LINE_CODING_PARAMETER CDC_VCP_LineCoding =
{
115200, /* baud rate */
0x00, /* stop bits-1 */
0x00, /* parity - none */
0x08 /* nb. of bits 8 */
};
extern TX_QUEUE tx_app_cmd_queue; /* Command queue for the application thread */
TX_THREAD ux_usb_cdc_read_thread;
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/* USER CODE BEGIN 1 */
VOID usbx_cdc_acm_read_thread_entry(ULONG thread_input) {
/* Private Variables */
UNUSED(thread_input);
ULONG __aligned(4) rx_actual_length;
uint8_t __aligned(4) UserRxBuffer[64];
printf("USBX CDC ACM Read Thread Started\n");
/* Infinite Loop */
while (1) {
if (cdc_acm != UX_NULL) {
// printf("Reading from USB CDC ACM... at pointer: %p\r\n", (void*)cdc_acm);
ux_device_class_cdc_acm_read(cdc_acm, (UCHAR*)UserRxBuffer, 64, &rx_actual_length);
if (rx_actual_length == 0) {
printf("No data received from USB CDC ACM, sleeping...\r\n");
tx_thread_sleep(5); // Sleep for a while if no data received
continue; // Skip to the next iteration
}
printf("Received %lu bytes from USB CDC ACM\r\n", rx_actual_length);
// We actually read something, so we can process it
for (uint32_t i = 0; i < rx_actual_length; i++) {
if (!putCharToRingBuffer(&vcpRxRingBuffer2, UserRxBuffer[i])) {
printf("Error: Failed to put character to VCP ring buffer\r\n");
}
}
UartUSBReady = SET; /* Set the flag to indicate that data is ready */
// Shorter sleep if receiving to help with straming
tx_thread_sleep(2);
} else {
printf("Error: cdc_acm is NULL, cannot read data\r\n");
tx_thread_sleep(100); /* Sleep for a while if cdc_acm is NULL */
}
}
}
void tx_vcp_usb_thread_entry(ULONG thread_input) {
UNUSED(thread_input);
printf("VCP USB HL Thread Started\r\n");
char tempChar = 0;
uint16_t cmdBytesRead = 0;
while (1) {
/* Wait for data to be received */
if (UartUSBReady == SET) {
UartUSBReady = RESET; /* Reset the flag */
// Read from the ring buffer
uint32_t availableCount = uart_ringbuf_get_available_count(&vcpRxRingBuffer2);
if (availableCount > 0) {
uint32_t bytesRead = 0;
while (bytesRead < availableCount && bytesRead <= TX_UART_RX_MAX_CMD_SIZE) {
if (cmdBytesRead >= TX_UART_RX_MAX_CMD_SIZE) {
printf("Error: Command buffer overflow\r\n");
memset((uint8_t*)tempVcpThreadReadBuff2, 0, TX_UART_RX_MAX_CMD_SIZE); /* Clear the ring buffer structure */
cmdBytesRead = 0; /* Reset the command bytes read counter */
break; /* Exit if we reach the maximum command size */
}
if (getCharFromRingBuffer(&vcpRxRingBuffer2, (uint8_t*)&tempChar)) {
bytesRead++; /* Increment the bytes read counter */
if (tempChar == '\r') tempChar = '\n'; /* Convert carriage return to newline for consistency */
tempVcpThreadReadBuff2[cmdBytesRead++] = tempChar; /* Store the character in the temporary buffer */
// Check for line delimiter
if (tempChar == TX_UART_LINE_DLIM_1 || tempChar == TX_UART_LINE_DLIM_2 || tempChar == TX_UART_LINE_DLIM_3) {
tempVcpThreadReadBuff2[cmdBytesRead] = '\0'; /* Null-terminate the string */
if (cmdBytesRead >= TX_UART_RX_MAX_CMD_SIZE) {
printf("Error: Command buffer overflow\r\n");
memset((uint8_t*)tempVcpThreadReadBuff2, 0, TX_UART_RX_MAX_CMD_SIZE); /* Clear the ring buffer structure */
cmdBytesRead = 0; /* Reset the command bytes read counter */
break; /* Exit if we reach the maximum command size */
} else if (cmdBytesRead <= 2) {
memset((uint8_t*)tempVcpThreadReadBuff2, 0, TX_UART_RX_MAX_CMD_SIZE); /* Clear the ring buffer structure */
cmdBytesRead = 0; /* Reset the command bytes read counter */
break; /* Exit if we receive an empty command */
}
if (strlen((char*)tempVcpThreadReadBuff2) <= 2) {
memset((uint8_t*)tempVcpThreadReadBuff2, 0, TX_UART_RX_MAX_CMD_SIZE); /* Clear the ring buffer structure */
cmdBytesRead = 0; /* Reset the command bytes read counter */
break; /* Exit if we receive a command that is too short */
}
// Be extra-safe and replace any remaining line delimiters with null terminators
for (uint16_t i = 0; i < cmdBytesRead; i++) {
if (tempVcpThreadReadBuff2[i] == TX_UART_LINE_DLIM_1 ||
tempVcpThreadReadBuff2[i] == TX_UART_LINE_DLIM_2 ||
tempVcpThreadReadBuff2[i] == TX_UART_LINE_DLIM_3) {
tempVcpThreadReadBuff2[i] = '\0'; /* Null-terminate the string */
}
}
// Queue the command in application command queue
cmd_queue_put_message((unsigned char*)tempVcpThreadReadBuff2, UART_VCP_USB); /* Put the command into the command queue */
memset((uint8_t*)tempVcpThreadReadBuff2, 0, TX_UART_RX_MAX_CMD_SIZE); /* Clear the ring buffer structure */
cmdBytesRead = 0; /* Reset the command bytes read counter */
break; /* Stop reading if we reach the line delimiter */
}
} else {
printf("Error: Failed to get character from ring buffer\r\n");
break; /* Exit if we cannot read more characters */
}
}
}
}
tx_thread_sleep(5); /* Sleep for a while to avoid busy waiting */
}
}
/* USER CODE END 1 */app_usbx_device.c
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file app_usbx_device.c
* @author MCD Application Team
* @brief USBX Device applicative file
******************************************************************************
* @attention
*
* Copyright (c) 2025 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "app_usbx_device.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "main.h"
#include "usb.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
static ULONG cdc_acm_interface_number;
static ULONG cdc_acm_configuration_number;
static UX_SLAVE_CLASS_CDC_ACM_PARAMETER cdc_acm_parameter;
static TX_THREAD ux_device_app_thread;
/* USER CODE BEGIN PV */
extern PCD_HandleTypeDef hpcd_USB_DRD_FS;
static TX_THREAD ux_cdc_read_thread;
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
static VOID app_ux_device_thread_entry(ULONG thread_input);
static UINT USBD_ChangeFunction(ULONG Device_State);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/**
* @brief Application USBX Device Initialization.
* @PAram memory_ptr: memory pointer
* @retval status
*/
UINT MX_USBX_Device_Init(VOID* memory_ptr) {
UINT ret = UX_SUCCESS;
UCHAR* device_framework_high_speed;
UCHAR* device_framework_full_speed;
ULONG device_framework_hs_length;
ULONG device_framework_fs_length;
ULONG string_framework_length;
ULONG language_id_framework_length;
UCHAR* string_framework;
UCHAR* language_id_framework;
UCHAR* pointer;
TX_BYTE_POOL* byte_pool = (TX_BYTE_POOL*)memory_ptr;
/* USER CODE BEGIN MX_USBX_Device_Init0 */
/* USER CODE END MX_USBX_Device_Init0 */
/* Allocate the stack for USBX Memory */
if (tx_byte_allocate(byte_pool, (VOID**)&pointer,
USBX_DEVICE_MEMORY_STACK_SIZE, TX_NO_WAIT) != TX_SUCCESS) {
/* USER CODE BEGIN USBX_ALLOCATE_STACK_ERROR */
return TX_POOL_ERROR;
/* USER CODE END USBX_ALLOCATE_STACK_ERROR */
}
/* Initialize USBX Memory */
if (ux_system_initialize(pointer, USBX_DEVICE_MEMORY_STACK_SIZE, UX_NULL, 0) != UX_SUCCESS) {
/* USER CODE BEGIN USBX_SYSTEM_INITIALIZE_ERROR */
return UX_ERROR;
/* USER CODE END USBX_SYSTEM_INITIALIZE_ERROR */
}
/* Get Device Framework High Speed and get the length */
device_framework_high_speed = USBD_Get_Device_Framework_Speed(USBD_HIGH_SPEED,
&device_framework_hs_length);
/* Get Device Framework Full Speed and get the length */
device_framework_full_speed = USBD_Get_Device_Framework_Speed(USBD_FULL_SPEED,
&device_framework_fs_length);
/* Get String Framework and get the length */
string_framework = USBD_Get_String_Framework(&string_framework_length);
/* Get Language Id Framework and get the length */
language_id_framework = USBD_Get_Language_Id_Framework(&language_id_framework_length);
/* Install the device portion of USBX */
if (ux_device_stack_initialize(device_framework_high_speed,
device_framework_hs_length,
device_framework_full_speed,
device_framework_fs_length,
string_framework,
string_framework_length,
language_id_framework,
language_id_framework_length,
USBD_ChangeFunction) != UX_SUCCESS) {
/* USER CODE BEGIN USBX_DEVICE_INITIALIZE_ERROR */
printf("Error: USBX Device initialization failed\n");
return UX_ERROR;
/* USER CODE END USBX_DEVICE_INITIALIZE_ERROR */
}
/* Initialize the cdc acm class parameters for the device */
cdc_acm_parameter.ux_slave_class_cdc_acm_instance_activate = USBD_CDC_ACM_Activate;
cdc_acm_parameter.ux_slave_class_cdc_acm_instance_deactivate = USBD_CDC_ACM_Deactivate;
cdc_acm_parameter.ux_slave_class_cdc_acm_parameter_change = USBD_CDC_ACM_ParameterChange;
/* USER CODE BEGIN CDC_ACM_PARAMETER */
/* USER CODE END CDC_ACM_PARAMETER */
/* Get cdc acm configuration number */
cdc_acm_configuration_number = USBD_Get_Configuration_Number(CLASS_TYPE_CDC_ACM, 0);
/* Find cdc acm interface number */
cdc_acm_interface_number = USBD_Get_Interface_Number(CLASS_TYPE_CDC_ACM, 0);
/* Initialize the device cdc acm class */
if (ux_device_stack_class_register(_ux_system_slave_class_cdc_acm_name,
ux_device_class_cdc_acm_entry,
cdc_acm_configuration_number,
cdc_acm_interface_number,
&cdc_acm_parameter) != UX_SUCCESS) {
/* USER CODE BEGIN USBX_DEVICE_CDC_ACM_REGISTER_ERROR */
return UX_ERROR;
/* USER CODE END USBX_DEVICE_CDC_ACM_REGISTER_ERROR */
}
/* Allocate the stack for device application main thread */
if (tx_byte_allocate(byte_pool, (VOID**)&pointer, UX_DEVICE_APP_THREAD_STACK_SIZE,
TX_NO_WAIT) != TX_SUCCESS) {
/* USER CODE BEGIN MAIN_THREAD_ALLOCATE_STACK_ERROR */
return TX_POOL_ERROR;
/* USER CODE END MAIN_THREAD_ALLOCATE_STACK_ERROR */
}
/* Create the device application main thread */
if (tx_thread_create(&ux_device_app_thread, UX_DEVICE_APP_THREAD_NAME, app_ux_device_thread_entry,
0, pointer, UX_DEVICE_APP_THREAD_STACK_SIZE, UX_DEVICE_APP_THREAD_PRIO,
UX_DEVICE_APP_THREAD_PREEMPTION_THRESHOLD, UX_DEVICE_APP_THREAD_TIME_SLICE,
UX_DEVICE_APP_THREAD_START_OPTION) != TX_SUCCESS) {
/* USER CODE BEGIN MAIN_THREAD_CREATE_ERROR */
return TX_THREAD_ERROR;
/* USER CODE END MAIN_THREAD_CREATE_ERROR */
}
/* USER CODE BEGIN MX_USBX_Device_Init1 */
/* Allocate the stack for usbx cdc acm read thread */
if (tx_byte_allocate(byte_pool, (VOID**)&pointer, 1024, TX_NO_WAIT) != TX_SUCCESS) {
printf("Error: Failed to allocate memory for usbx cdc acm read thread\n");
return TX_POOL_ERROR;
}
/* Create the usbx_cdc_acm_read_thread_entry thread */
if (tx_thread_create(&ux_cdc_read_thread, "cdc_acm_read_usbx_app_thread_entry",
usbx_cdc_acm_read_thread_entry, 1, pointer,
1024, 9, 9, TX_NO_TIME_SLICE,
TX_AUTO_START) != TX_SUCCESS) {
printf("Error: Failed to create usbx cdc acm read thread\n");
return TX_THREAD_ERROR;
}
/* Allocate the stack for usbx cdc acm LHL Read thread */
if (tx_byte_allocate(byte_pool, (VOID**)&pointer, 1024, TX_NO_WAIT) != TX_SUCCESS) {
printf("Error: Failed to allocate memory for usbx cdc acm HL read thread\n");
return TX_POOL_ERROR;
}
/* Create the usbx_cdc_acm_read_thread_entry thread */
if (tx_thread_create(&ux_usb_cdc_read_thread, "cdc_usb_acm_read_usbx_app_thread_entry",
tx_vcp_usb_thread_entry, 1, pointer,
1024, 9, 9, TX_NO_TIME_SLICE,
TX_AUTO_START) != TX_SUCCESS) {
printf("Error: Failed to create usbx cdc acm HL read thread\n");
return TX_THREAD_ERROR;
}
/* USER CODE END MX_USBX_Device_Init1 */
return ret;
}
/**
* @brief Function implementing app_ux_device_thread_entry.
* @PAram thread_input: User thread input parameter.
* @retval none
*/
static VOID app_ux_device_thread_entry(ULONG thread_input) {
/* USER CODE BEGIN app_ux_device_thread_entry */
printf("USBX Device Thread Started\n");
TX_PARAMETER_NOT_USED(thread_input);
/* Init the UART Rx Ring Buffer*/
UART_Init_Rx_Ringbuf(&vcpRxRingBuffer2, (uint8_t*)vcpRxBuffer2, TX_UART_RX_RINGBUF_SIZE);
HAL_PWREx_EnableVddUSB();
/* USB_DRD_FS init function */
MX_USB_PCD_Init();
/*USB packet memory area configuration*/
HAL_PCDEx_PMAConfig(&hpcd_USB_DRD_FS, 0x00, PCD_SNG_BUF, 0x14);
HAL_PCDEx_PMAConfig(&hpcd_USB_DRD_FS, 0x80, PCD_SNG_BUF, 0x54);
HAL_PCDEx_PMAConfig(&hpcd_USB_DRD_FS, USBD_CDCACM_EPOUT_ADDR, PCD_SNG_BUF, 0x94);
HAL_PCDEx_PMAConfig(&hpcd_USB_DRD_FS, USBD_CDCACM_EPIN_ADDR, PCD_SNG_BUF, 0x98);
HAL_PCDEx_PMAConfig(&hpcd_USB_DRD_FS, USBD_CDCACM_EPINCMD_ADDR, PCD_SNG_BUF, 0x9C);
/* initialize the device controller driver*/
ux_dcd_stm32_initialize((ULONG)USB_DRD_FS, (ULONG)&hpcd_USB_DRD_FS);
/* Start device USB */
HAL_PCD_Start(&hpcd_USB_DRD_FS);
while (1) {
/* Check if the device is connected */
tx_thread_sleep(100);
}
/* USER CODE END app_ux_device_thread_entry */
}
/**
* @brief USBD_ChangeFunction
* This function is called when the device state changes.
* @PAram Device_State: USB Device State
* @retval status
*/
static UINT USBD_ChangeFunction(ULONG Device_State) {
UINT status = UX_SUCCESS;
/* USER CODE BEGIN USBD_ChangeFunction0 */
/* USER CODE END USBD_ChangeFunction0 */
switch (Device_State) {
case UX_DEVICE_ATTACHED:
/* USER CODE BEGIN UX_DEVICE_ATTACHED */
printf("USB Device Attached\r\n");
/* USER CODE END UX_DEVICE_ATTACHED */
break;
case UX_DEVICE_REMOVED:
/* USER CODE BEGIN UX_DEVICE_REMOVED */
printf("USB Device Removed\r\n");
/* USER CODE END UX_DEVICE_REMOVED */
break;
case UX_DCD_STM32_DEVICE_CONNECTED:
/* USER CODE BEGIN UX_DCD_STM32_DEVICE_CONNECTED */
printf("USB Device Connected\r\n");
/* USER CODE END UX_DCD_STM32_DEVICE_CONNECTED */
break;
case UX_DCD_STM32_DEVICE_DISCONNECTED:
/* USER CODE BEGIN UX_DCD_STM32_DEVICE_DISCONNECTED */
printf("USB Device Disconnected\r\n");
/* USER CODE END UX_DCD_STM32_DEVICE_DISCONNECTED */
break;
case UX_DCD_STM32_DEVICE_SUSPENDED:
/* USER CODE BEGIN UX_DCD_STM32_DEVICE_SUSPENDED */
printf("USB Device Suspended\r\n");
/* USER CODE END UX_DCD_STM32_DEVICE_SUSPENDED */
break;
case UX_DCD_STM32_DEVICE_RESUMED:
/* USER CODE BEGIN UX_DCD_STM32_DEVICE_RESUMED */
printf("USB Device Resumed\r\n");
/* USER CODE END UX_DCD_STM32_DEVICE_RESUMED */
break;
case UX_DCD_STM32_SOF_RECEIVED:
/* USER CODE BEGIN UX_DCD_STM32_SOF_RECEIVED */
/* USER CODE END UX_DCD_STM32_SOF_RECEIVED */
break;
default:
/* USER CODE BEGIN DEFAULT */
/* USER CODE END DEFAULT */
break;
}
/* USER CODE BEGIN USBD_ChangeFunction1 */
/* USER CODE END USBD_ChangeFunction1 */
return status;
}
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */The above code worked flawlessly, USB enumerated correctly, and as far as I could tell, nothing looked out of place using UPCap to debug the USB handshake or bulk transfers.
Then I tried making a composite device...
Using CubeMX to make a composite CDC ACM and CustomHID and using my codemod to unpack the above structs did not work. I could not get the composite descriptor to send any strings properly, and the device would not enumerate properly in windows. I was a bit stumped, but I figured that the compiler was adding in some extra zero-padding to the descriptor structs to make the members 32Bit-Aligned.
I then re-generated the code without my codemod, effectively keeping the stock USBX code CubeMX generated. This immediately resulted in the same UNALIGNED hard fault as before. Again, I'm absolutely sure the MPU is not enabled. Back to square one!
More to follow...
