This question is a follow up to this one:
https://community.arm.com/developer/tools-software/tools/f/keil-forum/47193/implementing-a-non-hanging-usb-listener/166340#166340
trying to narrow down the cause of USB blocking thread creation.
I'm unable to find the implementation for the USBD_Initialize() and USBD_Connect() functions in app_main(), in main.c from the "USB Device Virtual COM (MCB1700)" sample code:
main.c:
/*------------------------------------------------------------------------------ * Example main module * Copyright (c) 2019 Arm Limited (or its affiliates). All rights reserved. *------------------------------------------------------------------------------ * Name: main.c * Purpose: Main module *----------------------------------------------------------------------------*/ #include "cmsis_os2.h" // ::CMSIS:RTOS2 #include "LPC17xx.h" // Device header #include "Board_GLCD.h" // ::Board Support:Graphic LCD extern void app_main (void *arg); extern const osThreadAttr_t app_main_attr; /*------------------------------------------------------------------------------ * main function *----------------------------------------------------------------------------*/ int main(void) { SystemCoreClockUpdate (); // Update System Core Clock info GLCD_Initialize (); // Initialize Graphical LCD osKernelInitialize (); // Initialize CMSIS-RTOS2 osThreadNew (app_main, NULL, &app_main_attr); // Create application main thread osKernelStart (); // Start thread execution for (;;) {} }
app_main() contains the USB init/connect code and is defined in VirtualCom.c:
/*------------------------------------------------------------------------------ * MDK Middleware - Component ::USB:Device * Copyright (c) 2004-2019 Arm Limited (or its affiliates). All rights reserved. *------------------------------------------------------------------------------ * Name: VirtualCOM.c * Purpose: USB Device - Virtual COM Port example *----------------------------------------------------------------------------*/ #include "rl_usb.h" // Keil.MDK-Pro::USB:CORE #include "Board_GLCD.h" // ::Board Support:Graphic LCD #include "GLCD_Config.h" // Keil.MCB1700::Board Support:Graphic LCD // Main stack size must be multiple of 8 Bytes #define APP_MAIN_STK_SZ (1024U) static uint64_t app_main_stk[APP_MAIN_STK_SZ / 8]; const osThreadAttr_t app_main_attr = { .stack_mem = &app_main_stk[0], .stack_size = sizeof(app_main_stk) }; extern GLCD_FONT GLCD_Font_6x8; extern GLCD_FONT GLCD_Font_16x24; __NO_RETURN void app_main (void *arg); /*------------------------------------------------------------------------------ * Application *----------------------------------------------------------------------------*/ __NO_RETURN void app_main (void *arg) { (void)arg; GLCD_SetBackgroundColor (GLCD_COLOR_BLUE); GLCD_SetForegroundColor (GLCD_COLOR_WHITE); GLCD_ClearScreen (); GLCD_SetFont (&GLCD_Font_16x24); GLCD_DrawString (0U, 0U*24U, " USB Device "); GLCD_DrawString (0U, 1U*24U, " CDC ACM Class "); GLCD_DrawString (0U, 2U*24U, " VirtualCOM Example "); GLCD_DrawString (0U, 4U*24U, " USB <-> UART1 "); GLCD_DrawString (0U, 8U*24U, " Keil Tools by ARM "); GLCD_DrawString (0U, 9U*24U, " www.keil.com "); USBD_Initialize (0U); // USB Device 0 Initialization USBD_Connect (0U); // USB Device 0 Connect osThreadExit(); }
Where are USBD_Initialize() and USBD_Connect() implemented? Looking through the rest of the sample declarations can be found in
rl_usb.h:
/// \brief Initialize USB Device stack and controller /// \param[in] device index of USB Device. /// \return status code that indicates the execution status of the function as defined with \ref usbStatus. extern usbStatus USBD_Initialize (uint8_t device); extern usbStatus USBD_Connect (uint8_t device);
but I couldn't find a matching implementation file (F12 returns no matching function signatures); the only definitions found were in USBD_lpc17xx.c:
/** \fn int32_t USBD_Initialize (ARM_USBD_SignalDeviceEvent_t cb_device_event, ARM_USBD_SignalEndpointEvent_t cb_endpoint_event) \brief Initialize USB Device Interface. \param[in] cb_device_event Pointer to \ref ARM_USBD_SignalDeviceEvent \param[in] cb_endpoint_event Pointer to \ref ARM_USBD_SignalEndpointEvent \return \ref execution_status */ static int32_t USBD_Initialize (ARM_USBD_SignalDeviceEvent_t cb_device_event, ARM_USBD_SignalEndpointEvent_t cb_endpoint_event) { if ((usb_state & USBD_DRIVER_INITIALIZED) != 0U) { return ARM_DRIVER_OK; } SignalDeviceEvent = cb_device_event; SignalEndpointEvent = cb_endpoint_event; usb_role = ARM_USB_ROLE_DEVICE; if (USB_PinsConfigure () == -1) { usb_role = ARM_USB_ROLE_NONE; return ARM_DRIVER_ERROR; } usb_state |= USBD_DRIVER_INITIALIZED; return ARM_DRIVER_OK; }
where USB_PinsConfigure() is defined in OTG_lpc17xx.c:
/** \fn int32_t USB_PinsConfigure (void) \brief Configure USB pins \return result of pin configuration - value 0: pins configured correctly - value -1: pins configuration has failed */ int32_t USB_PinsConfigure (void) { #if defined (LPC177x_8x) volatile uint8_t U1_role = 0U; // NOT DEFINED volatile uint8_t U2_role = 0U; // NOT DEFINED #endif if (usb_pin_cfg == 1U) { return 0U; } usb_pin_cfg = 0U; #if defined (LPC175x_6x) switch (usb_role) { // Host pins case ARM_USB_ROLE_HOST: #if (RTE_USB_PPWR_PIN_EN == 1) // P1.19 - USB_PPWR -- PIN NOT DEFINED if (PIN_Configure (1, 19, PIN_FUNC_2, PIN_PINMODE_PULLUP, PIN_PINMODE_NORMAL) != 0) { return -1; } #endif #if (RTE_USB_PWRD_PIN_EN == 1) // P1.22 - USB_PWRD -- PIN NOT DEFINED if (PIN_Configure (1, 22, PIN_FUNC_2, PIN_PINMODE_TRISTATE, PIN_PINMODE_NORMAL) != 0) { return -1; } #endif #if (RTE_USB_OVRCR_PIN_EN == 1) // P1.27 - USB_OVRCR if (PIN_Configure (1, 27, PIN_FUNC_2, PIN_PINMODE_TRISTATE, PIN_PINMODE_NORMAL) != 0) { return -1; } #endif break; // Device pins case ARM_USB_ROLE_DEVICE: #if (RTE_USB_CONNECT_PIN_EN == 1) // P2.9 SoftConnect if (PIN_Configure (2, 9, PIN_FUNC_1, PIN_PINMODE_PULLDOWN, PIN_PINMODE_NORMAL) != 0) { return -1; } // NOT DEFINED #endif #if (RTE_USB_VBUS_PIN_EN == 1) // P1.30 VBUS if (PIN_Configure (1, 30, PIN_FUNC_2, PIN_PINMODE_TRISTATE, PIN_PINMODE_NORMAL) != 0) { return -1; } #endif break; default: return -1; } // Common pins configuration #if (RTE_USB_UP_LED_PIN_EN == 1) // P1.18 GoodLink if (PIN_Configure (1, 18, PIN_FUNC_1, PIN_PINMODE_PULLUP, PIN_PINMODE_NORMAL) != 0) { return -1; } #endif // P0.29 D+ if (PIN_Configure (0, 29, PIN_FUNC_1, PIN_PINMODE_TRISTATE, PIN_PINMODE_NORMAL) != 0) { return -1; } // P0.30 D- if (PIN_Configure (0, 30, PIN_FUNC_1, PIN_PINMODE_TRISTATE, PIN_PINMODE_NORMAL) != 0) { return -1; } usb_pin_cfg = 1U; return 0U;
Pins 1.19 and 1.22 (USB host config) are not connected:
and in the sample file USB_User_CDC_ACM_UART.c:
// Called during USBD_Initialize to initialize the USB CDC class instance (ACM). void USBD_CDC0_ACM_Initialize (void) { ptrUART->Initialize (UART_Callback); ptrUART->PowerControl (ARM_POWER_FULL); #ifdef USB_CMSIS_RTOS2 cdc_acm_bridge_tid = osThreadNew (CDC0_ACM_UART_to_USB_Thread, NULL, &cdc0_acm_uart_to_usb_thread_attr); // NOT DEFINED #else cdc_acm_bridge_tid = osThreadCreate (osThread (CDC0_ACM_UART_to_USB_Thread), NULL); #endif }
the later which is "called during USBD_Initialize to initialize USB CDC class instance (ACM)" but where USBD_Initialize defined?
I'm not using RTOS2; a thread is created at line (on RTOS):
cdc_acm_bridge_tid = osThreadCreate (osThread (CDC0_ACM_UART_to_USB_Thread), NULL);
How can I find the total number of threads that the firmware creates? On RTOS it's in RTX_Conf_CM.c:
//-------- <<< Use Configuration Wizard in Context Menu >>> ----------------- // // <h>Thread Configuration // ======================= // // <o>Number of concurrent running user threads <1-250> // <i> Defines max. number of user threads that will run at the same time. // <i> Default: 6; #ifndef OS_TASKCNT #define OS_TASKCNT 5 #endif
I'm not sure how many threads are created by either USBD_Initialize() and USBD_Connect(); at a glance, it's at least 1 in USBD_Initialize(). I already have 4 threads without the USB related code which makes a total of at least 5. Does RTOS2 specify a predefined number of threads?
At the moment, if USBD_Initialize() and USBD_Connect() are placed before any of the previous threads, a new COM port is created but the remaining threads fail to launch. If placed after thread creation, no COM ports are created.
Is it possible to have the lpc1768 as a USB device listener while also performing logic?
If yes, how can I go about it?
The current USB examples in keil use RTOS2; where can I find code that uses RTOS?
> What do you actually mean by "device listener" ?
The lpc listens on a serial port for a byte stream.