This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Implementing a non-hanging USB listener

I'm working with an LPC1768(FBD100) and need to connect to a PC through a serial USB. As a starting point, I used the sample package USB virtual com port.

Installed packages:

My code:

#include "includes.h"


int main (void) {
MenuEntryVType* MenuEntry;
GUI_Init();
WM_SetCreateFlags(WM_CF_MEMDEV);

FRAMEWIN_SetDefaultSkinClassic();
PROGBAR_SetDefaultSkinClassic();
SCROLLBAR_SetDefaultSkinClassic();
FRAMEWIN_SetDefaultFont(StdFont);

InitOutputs();
InitADCs();
InitDAC();
InitPWM(100);
InitI2C();
GetConfig();


osDelay(1500);


// Works as expected ; new COMx device shows in dev manager.
USBD_Initialize (0U); // USB Device 0 Initialization
USBD_Connect (0U); // USB Device 0 Connect


// menu handling code
// actual functionality start servos, etc.)
// does not get executed. Why?
return 0;
}

Why does USBD_Connect() hang? no code gets executed past that point; the lpc1768 does connect, however, to the PC:

rl_usb.h contains the definitions of USBD_Initialize() and USBD_Connect():

/// \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);

/// \brief Activate pull-up on D+ or D- line to signal USB Device connection on USB Bus
/// \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_Connect (uint8_t device);
 

These are function declarations; I don't know where the implementations are (likely in USB_CM3_L.lib).

Read/write functions are defined in USBD_User_CDC_ACM_UART_0.c

/*------------------------------------------------------------------------------
 * MDK Middleware - Component ::USB:Device
 * Copyright (c) 2004-2019 ARM Germany GmbH. All rights reserved.
 *------------------------------------------------------------------------------
 * Name:    USBD_User_CDC_ACM_UART_0.c
 * Purpose: USB Device Communication Device Class (CDC)
 *          Abstract Control Model (ACM) USB <-> UART Bridge User module
 * Rev.:    V1.0.3
 *----------------------------------------------------------------------------*/
/**
 * \addtogroup usbd_cdcFunctions
 *
 * USBD_User_CDC_ACM_UART_0.c implements the application specific
 * functionality of the CDC ACM class and is used to demonstrate a USB <-> UART
 * bridge. All data received on USB is transmitted on UART and all data
 * received on UART is transmitted on USB.
 *
 * Details of operation:
 *   UART -> USB:
 *     Initial reception on UART is started after the USB Host sets line coding
 *     with SetLineCoding command. Having received a full UART buffer, any
 *     new reception is restarted on the same buffer. Any data received on
 *     the UART is sent over USB using the CDC0_ACM_UART_to_USB_Thread thread.
 *   USB -> UART:
 *     While the UART transmit is not busy, data transmission on the UART is
 *     started in the USBD_CDC0_ACM_DataReceived callback as soon as data is
 *     received on the USB. Further data received on USB is transmitted on
 *     UART in the UART callback routine until there is no more data available.
 *     In this case, the next UART transmit is restarted from the
 *     USBD_CDC0_ACM_DataReceived callback as soon as new data is received
 *     on the USB.
 *
 * The following constants in this module affect the module functionality:
 *
 *  - UART_PORT:        specifies UART Port
 *      default value:  0 (=UART0)
 *  - UART_BUFFER_SIZE: specifies UART data Buffer Size
 *      default value:  512
 *
 * Notes:
 *   If the USB is slower than the UART, data can get lost. This may happen
 *   when USB is pausing during data reception because of the USB Host being
 *   too loaded with other tasks and not polling the Bulk IN Endpoint often
 *   enough (up to 2 seconds of gap in polling Bulk IN Endpoint may occur).
 *   This problem can be solved by using a large enough UART buffer to
 *   compensate up to a few seconds of received UART data or by using UART
 *   flow control.
 *   If the device that receives the UART data (usually a PC) is too loaded
 *   with other tasks it can also loose UART data. This problem can only be
 *   solved by using UART flow control.
 *
 *   This file has to be adapted in case of UART flow control usage.
 */
 
 
//! [code_USBD_User_CDC_ACM]
 
#include <stdbool.h>
#include "rl_usb.h"
 
#if defined(RTE_CMSIS_RTOS2)
  #include "cmsis_os2.h"
#if defined(RTE_CMSIS_RTOS2_RTX5)
  #include "rtx_os.h"
#endif
#endif
#if defined(RTE_CMSIS_RTOS)
  #include "cmsis_os.h"
#endif
 
#include "Driver_USART.h"
 
// UART Configuration ----------------------------------------------------------
 
#define  UART_PORT              1       // UART Port number
#define  UART_BUFFER_SIZE       512     // UART Buffer Size
 
//------------------------------------------------------------------------------
 
#define _UART_Driver_(n)        Driver_USART##n
#define  UART_Driver_(n)       _UART_Driver_(n)
extern   ARM_DRIVER_USART       UART_Driver_(UART_PORT);
#define  ptrUART              (&UART_Driver_(UART_PORT))
 
// External functions
#ifdef   USB_CMSIS_RTOS
extern   void                   CDC0_ACM_UART_to_USB_Thread (void const *arg) __attribute((noreturn));
#endif
 
// Local Variables
static            uint8_t       uart_rx_buf[UART_BUFFER_SIZE];
static            uint8_t       uart_tx_buf[UART_BUFFER_SIZE];
 
static   volatile int32_t       uart_rx_cnt         =   0;
static   volatile int32_t       usb_tx_cnt          =   0;
 
static   void                  *cdc_acm_bridge_tid  =   0U;
static   CDC_LINE_CODING        cdc_acm_line_coding = { 0U, 0U, 0U, 0U };
 
 
// Called when UART has transmitted or received requested number of bytes.
// \param[in]   event         UART event
//               - ARM_USART_EVENT_SEND_COMPLETE:    all requested data was sent
//               - ARM_USART_EVENT_RECEIVE_COMPLETE: all requested data was received
static void UART_Callback (uint32_t event) {
  int32_t cnt;
 
  if (event & ARM_USART_EVENT_SEND_COMPLETE) {
    // USB -> UART
    cnt = USBD_CDC_ACM_ReadData(0U, uart_tx_buf, UART_BUFFER_SIZE);
    if (cnt > 0) {
      ptrUART->Send(uart_tx_buf, (uint32_t)(cnt));
    }
  }
 
  if (event & ARM_USART_EVENT_RECEIVE_COMPLETE) {
    // UART data received, restart new reception
    uart_rx_cnt += UART_BUFFER_SIZE;
    ptrUART->Receive(uart_rx_buf, UART_BUFFER_SIZE);
  }
}
 
// Thread: Sends data received on UART to USB
// \param[in]     arg           not used.
#ifdef USB_CMSIS_RTOS2
__NO_RETURN static void CDC0_ACM_UART_to_USB_Thread (void *arg) {
#else
__NO_RETURN        void CDC0_ACM_UART_to_USB_Thread (void const *arg) {
#endif
  int32_t cnt, cnt_to_wrap;
 
  (void)(arg);
 
  while (1) {
    // UART - > USB
    if (ptrUART->GetStatus().rx_busy != 0U) {
      cnt  = uart_rx_cnt;
      cnt += ptrUART->GetRxCount();
      cnt -= usb_tx_cnt;
      if (cnt >= UART_BUFFER_SIZE) {
        // Dump data received on UART if USB is not consuming fast enough
        usb_tx_cnt += cnt;
        cnt = 0U;
      }
      if (cnt > 0) {
        cnt_to_wrap = (int32_t)(UART_BUFFER_SIZE - ((uint32_t)usb_tx_cnt & (UART_BUFFER_SIZE - 1)));
        if (cnt > cnt_to_wrap) {
          cnt = cnt_to_wrap;
        }
        cnt = USBD_CDC_ACM_WriteData(0U, (uart_rx_buf + ((uint32_t)usb_tx_cnt & (UART_BUFFER_SIZE - 1))), cnt);
        if (cnt > 0) {
          usb_tx_cnt += cnt;
        }
      }
    }
    osDelay(10U);
  }
}
#ifdef USB_CMSIS_RTOS2
#ifdef USB_CMSIS_RTOS2_RTX5
static osRtxThread_t        cdc0_acm_uart_to_usb_thread_cb_mem               __SECTION(.bss.os.thread.cb);
static uint64_t             cdc0_acm_uart_to_usb_thread_stack_mem[512U / 8U] __SECTION(.bss.os.thread.stack);
#endif
static const osThreadAttr_t cdc0_acm_uart_to_usb_thread_attr = {
  "CDC0_ACM_UART_to_USB_Thread",
  0U,
#ifdef USB_CMSIS_RTOS2_RTX5
 &cdc0_acm_uart_to_usb_thread_cb_mem,
  sizeof(osRtxThread_t),
 &cdc0_acm_uart_to_usb_thread_stack_mem[0],
#else
  NULL,
  0U,
  NULL,
#endif
  512U,
  osPriorityNormal,
  0U,
  0U
};
#else
extern const osThreadDef_t os_thread_def_CDC0_ACM_UART_to_USB_Thread;
osThreadDef (CDC0_ACM_UART_to_USB_Thread, osPriorityNormal, 1U, 0U);
#endif
 
 
// CDC ACM Callbacks -----------------------------------------------------------
 
// Called when new data was received from the USB Host.
// \param[in]   len           number of bytes available to read.
void USBD_CDC0_ACM_DataReceived (uint32_t len) {
  int32_t cnt;
 
  (void)(len);
 
  if (ptrUART->GetStatus().tx_busy == 0U) {
    // Start USB -> UART
    cnt = USBD_CDC_ACM_ReadData(0U, uart_tx_buf, UART_BUFFER_SIZE);
    if (cnt > 0) {
      ptrUART->Send(uart_tx_buf, (uint32_t)(cnt));
    }
  }
}
 
// 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);
#else
  cdc_acm_bridge_tid = osThreadCreate (osThread (CDC0_ACM_UART_to_USB_Thread), NULL);
#endif
}
 
 
// Called during USBD_Uninitialize to de-initialize the USB CDC class instance (ACM).
void USBD_CDC0_ACM_Uninitialize (void) {
 
  if (osThreadTerminate (cdc_acm_bridge_tid) == osOK) {
    cdc_acm_bridge_tid = NULL;
  }
 
  ptrUART->Control      (ARM_USART_ABORT_RECEIVE, 0U);
  ptrUART->PowerControl (ARM_POWER_OFF);
  ptrUART->Uninitialize ();
}
 
 
// Called upon USB Bus Reset Event.
void USBD_CDC0_ACM_Reset (void) {
  ptrUART->Control      (ARM_USART_ABORT_SEND,    0U);
  ptrUART->Control      (ARM_USART_ABORT_RECEIVE, 0U);
}
 
 
// Called upon USB Host request to change communication settings.
// \param[in]   line_coding   pointer to CDC_LINE_CODING structure.
// \return      true          set line coding request processed.
// \return      false         set line coding request not supported or not processed.
bool USBD_CDC0_ACM_SetLineCoding (const CDC_LINE_CODING *line_coding) {
  uint32_t data_bits = 0U, parity = 0U, stop_bits = 0U;
  int32_t  status;
 
  ptrUART->Control (ARM_USART_ABORT_SEND,    0U);
  ptrUART->Control (ARM_USART_ABORT_RECEIVE, 0U);
  ptrUART->Control (ARM_USART_CONTROL_TX,    0U);
  ptrUART->Control (ARM_USART_CONTROL_RX,    0U);
 
  switch (line_coding->bCharFormat) {
    case 0:                             // 1 Stop bit
      stop_bits = ARM_USART_STOP_BITS_1;
      break;
    case 1:                             // 1.5 Stop bits
      stop_bits = ARM_USART_STOP_BITS_1_5;
      break;
    case 2:                             // 2 Stop bits
      stop_bits = ARM_USART_STOP_BITS_2;
  }
 
  switch (line_coding->bParityType) {
    case 0:                             // None
      parity = ARM_USART_PARITY_NONE;
      break;
    case 1:                             // Odd
      parity = ARM_USART_PARITY_ODD;
      break;
    case 2:                             // Even
      parity = ARM_USART_PARITY_EVEN;
      break;
    default:
      return false;
  }
 
  switch (line_coding->bDataBits) {
    case 5:
      data_bits = ARM_USART_DATA_BITS_5;
      break;
    case 6:
      data_bits = ARM_USART_DATA_BITS_6;
      break;
    case 7:
      data_bits = ARM_USART_DATA_BITS_7;
      break;
    case 8:
      data_bits = ARM_USART_DATA_BITS_8;
      break;
    default:
      return false;
  }
 
  status = ptrUART->Control(ARM_USART_MODE_ASYNCHRONOUS  |
                            data_bits                    |
                            parity                       |
                            stop_bits                    |
                            ARM_USART_FLOW_CONTROL_NONE  ,
                            line_coding->dwDTERate       );

  if (status != ARM_DRIVER_OK) {
    return false;
  }
 
  // Store requested settings to local variable
  cdc_acm_line_coding = *line_coding;
 
  uart_rx_cnt = 0;
  usb_tx_cnt  = 0;
 
  ptrUART->Control (ARM_USART_CONTROL_TX, 1U);
  ptrUART->Control (ARM_USART_CONTROL_RX, 1U);
 
  ptrUART->Receive (uart_rx_buf, UART_BUFFER_SIZE);
 
  return true;
}
 
 
// Called upon USB Host request to retrieve communication settings.
// \param[out]  line_coding   pointer to CDC_LINE_CODING structure.
// \return      true          get line coding request processed.
// \return      false         get line coding request not supported or not processed.
bool USBD_CDC0_ACM_GetLineCoding (CDC_LINE_CODING *line_coding) {
 
  // Load settings from ones stored on USBD_CDC0_ACM_SetLineCoding callback
  *line_coding = cdc_acm_line_coding;
 
  return true;
}
 
 
// Called upon USB Host request to set control line states.
// \param [in]  state         control line settings bitmap.
//                - bit 0: DTR state
//                - bit 1: RTS state
// \return      true          set control line state request processed.
// \return      false         set control line state request not supported or not processed.
bool USBD_CDC0_ACM_SetControlLineState (uint16_t state) {
  // Add code for set control line state
 
  (void)(state);
 
  return true;
}
 
//! [code_USBD_User_CDC_ACM]

Is it possible to run the lpc1768 as a USB listener and also perform a set of tasks in parallel? If yes, how should I go about it?

Parents Reply Children
  • "I'm working with an LPC1768(FBD100) ... " USB layout: P1.30, P0.29, P0.30. I've read the schematic and have already integrated the example into my code; the problem is that I don't know if the mcu can listen on a usb port while running other threads.

  • Of course it can, USB functionality runs in separate threads so other threads can execute in parallel.

  • When I create a separate thread that does USBD_Initialize() and USBD_Connect() I don't see the device as a serial connection in device manager (every other thread executes successfully). There seems to be an issue in that code that should execute in threads does not if the USB related functionality is run before it. If the USB related logic is placed after the initial logic it does not execute either inside/outside a thread. 

  • Of course it can

    Indeed!

    It would be pretty useless if it didn't!

  • Before jumping into the complexities of USB. have you done some basic projects on this chip to gain familiarity with it and the tools ?

    Also, the USB stuff is proprietary to NXP - nothing to do with ARM or Keil - so you'd be better asking NXP about specific details of getting their USB in their chip to work ...

    https://community.nxp.com/

    Don't NXP provide any examples, demos, etc ... ?

    https://www.nxp.com/products/processors-and-microcontrollers/arm-microcontrollers/general-purpose-mcus/lpc1700-cortex-m3/512kb-flash-64kb-sram-ethernet-usb-lqfp100-package:LPC1768FBD100

  • You should analyze the code to better understand what and how to achieve what you want to achieve.

    Anyways, when you call USBD_Initialize it actually creates all the thread responsible for the USB handling behind the scenes, you could take a look at RTOS view to see which threads are running (http://www2.keil.com/mdk5/cmsis/rtx/rtos-awareness).

    You do not have to call USBD_Initialize from your thread, it is irrelevant.

    You should also analyze if you have enough of RTOS resources configured in RTX_Config.h file for all the threads and any other RTOS objects you are using in your project.

    Anyways, I would start from the MCB1700 VirtualCOM example, if it works, I would then add 1 new thread that just increments the counter and see if that works and then start adding additional functionality.

  • Took over a project (haven't worked with lpcxxxx; not new to embedded, however) that has to be extended with a polling mechanism that can only use USB. I've checked the samples but didn't see any USB specific code (maybe haven't looked hard enough). The sample code from keil works as expected with the exception that no further threads can be created once USB_Connect() is called. 

  • How many threads are created by the USB setup/connect code? RTOS seems to have an upper bound, OS_TASKCNT, that I set to 15 (from the original 5) to no effect.; not sure it's a thread count issue. Yes, it's unlikely that there aren;t enough resources since the serial device is created as expected if the code is placed before creating the remaining threads. I couldn't get the example to run; it builds fine but both the display and the USB code don;t work (or are not executed); I'm using  a default build with no configuration changes made. 

  • You can see details about number of threads and stack requirements here: http://www.keil.com/pack/doc/mw/USB/html/usb_resource_requirements.html#usbd_res_req

    BTW, if you are using CMSIS-RTOS2 RTX5 as OS then USB components statically allocate stack for their threads so they do not impact system stack setting.

    It should be easy to add a new thread and debug if creation of thread failed, and why.

  • Thanks! I'm using RTOS and have to define requirements; I'll post the config tomorrow. 

  • Wouldn't it be worth starting with a basic example without RTOS, and getting that working first?

  • The project already works; I'm only having trouble when using USB. 

  • Exactly - so have a new project where you can concentrate on just getting the USB working.

  • I already have a working USB project that needs to be integrated into an existing project. The latter uses RTOS and creates 4 threads. When I integrate the USB component two things happen depending on where the component is being placed:

    1. If it's placed before any of the application's threads than a COM port is created and the USB port written to which is fine except that no other threads are created past it. I'm still suspecting it's a resource related issue (a thread number or stack size limit that's being hit) 
    2. Placed after the application's logic, application works fine but no serial (COM) port shows in the device manager. 
  • These are the config files:

    startup_LPC17xx.s:

    ;/**************************************************************************//**
    ; * @file     startup_LPC17xx.s
    ; * @brief    CMSIS Cortex-M3 Core Device Startup File for
    ; *           NXP LPC17xx Device Series
    ; * @version  V1.10
    ; * @date     06. April 2011
    ; *
    ; * @note
    ; * Copyright (C) 2009-2011 ARM Limited. All rights reserved.
    ; *
    ; * @par
    ; * ARM Limited (ARM) is supplying this software for use with Cortex-M
    ; * processor based microcontrollers.  This file can be freely distributed
    ; * within development tools that are supporting such ARM based processors.
    ; *
    ; * @par
    ; * THIS SOFTWARE IS PROVIDED "AS IS".  NO WARRANTIES, WHETHER EXPRESS, IMPLIED
    ; * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
    ; * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
    ; * ARM SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR
    ; * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
    ; *
    ; ******************************************************************************/
    
    ; *------- <<< Use Configuration Wizard in Context Menu >>> ------------------
    
    ; <h> Stack Configuration
    ;   <o> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>
    ; </h>
    
    Stack_Size      EQU     0x00000200
    
                    AREA    STACK, NOINIT, READWRITE, ALIGN=3
    Stack_Mem       SPACE   Stack_Size
    __initial_sp
    
    
    ; <h> Heap Configuration
    ;   <o>  Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
    ; </h>
    
    Heap_Size       EQU     0x00000000
    
                    AREA    HEAP, NOINIT, READWRITE, ALIGN=3
    __heap_base
    Heap_Mem        SPACE   Heap_Size
    __heap_limit
    
    
                    PRESERVE8
                    THUMB
    
    
    ; Vector Table Mapped to Address 0 at Reset
    
                    AREA    RESET, DATA, READONLY
                    EXPORT  __Vectors
    
    __Vectors       DCD     __initial_sp              ; Top of Stack
                    DCD     Reset_Handler             ; Reset Handler
                    DCD     NMI_Handler               ; NMI Handler
                    DCD     HardFault_Handler         ; Hard Fault Handler
                    DCD     MemManage_Handler         ; MPU Fault Handler
                    DCD     BusFault_Handler          ; Bus Fault Handler
                    DCD     UsageFault_Handler        ; Usage Fault Handler
                    DCD     0                         ; Reserved
                    DCD     0                         ; Reserved
                    DCD     0                         ; Reserved
                    DCD     0                         ; Reserved
                    DCD     SVC_Handler               ; SVCall Handler
                    DCD     DebugMon_Handler          ; Debug Monitor Handler
                    DCD     0                         ; Reserved
                    DCD     PendSV_Handler            ; PendSV Handler
                    DCD     SysTick_Handler           ; SysTick Handler
    
                    ; External Interrupts
                    DCD     WDT_IRQHandler            ; 16: Watchdog Timer
                    DCD     TIMER0_IRQHandler         ; 17: Timer0
                    DCD     TIMER1_IRQHandler         ; 18: Timer1
                    DCD     TIMER2_IRQHandler         ; 19: Timer2
                    DCD     TIMER3_IRQHandler         ; 20: Timer3
                    DCD     UART0_IRQHandler          ; 21: UART0
                    DCD     UART1_IRQHandler          ; 22: UART1
                    DCD     UART2_IRQHandler          ; 23: UART2
                    DCD     UART3_IRQHandler          ; 24: UART3
                    DCD     PWM1_IRQHandler           ; 25: PWM1
                    DCD     I2C0_IRQHandler           ; 26: I2C0
                    DCD     I2C1_IRQHandler           ; 27: I2C1
                    DCD     I2C2_IRQHandler           ; 28: I2C2
                    DCD     SPI_IRQHandler            ; 29: SPI
                    DCD     SSP0_IRQHandler           ; 30: SSP0
                    DCD     SSP1_IRQHandler           ; 31: SSP1
                    DCD     PLL0_IRQHandler           ; 32: PLL0 Lock (Main PLL)
                    DCD     RTC_IRQHandler            ; 33: Real Time Clock
                    DCD     EINT0_IRQHandler          ; 34: External Interrupt 0
                    DCD     EINT1_IRQHandler          ; 35: External Interrupt 1
                    DCD     EINT2_IRQHandler          ; 36: External Interrupt 2
                    DCD     EINT3_IRQHandler          ; 37: External Interrupt 3
                    DCD     ADC_IRQHandler            ; 38: A/D Converter
                    DCD     BOD_IRQHandler            ; 39: Brown-Out Detect
                    DCD     USB_IRQHandler            ; 40: USB
                    DCD     CAN_IRQHandler            ; 41: CAN
                    DCD     DMA_IRQHandler            ; 42: General Purpose DMA
                    DCD     I2S_IRQHandler            ; 43: I2S
                    DCD     ENET_IRQHandler           ; 44: Ethernet
                    DCD     RIT_IRQHandler            ; 45: Repetitive Interrupt Timer
                    DCD     MCPWM_IRQHandler          ; 46: Motor Control PWM
                    DCD     QEI_IRQHandler            ; 47: Quadrature Encoder Interface
                    DCD     PLL1_IRQHandler           ; 48: PLL1 Lock (USB PLL)
                    DCD     USBActivity_IRQHandler    ; 49: USB Activity interrupt to wakeup
                    DCD     CANActivity_IRQHandler    ; 50: CAN Activity interrupt to wakeup
    
    
                    IF      :LNOT::DEF:NO_CRP
                    AREA    |.ARM.__at_0x02FC|, CODE, READONLY
    CRP_Key         DCD     0xFFFFFFFF
                    ENDIF
    
    
                    AREA    |.text|, CODE, READONLY
    
    
    ; Reset Handler
    
    Reset_Handler   PROC
                    EXPORT  Reset_Handler             [WEAK]
                    IMPORT  SystemInit
                    IMPORT  __main
                    LDR     R0, =SystemInit
                    BLX     R0
                    LDR     R0, =__main
                    BX      R0
                    ENDP
    
    
    ; Dummy Exception Handlers (infinite loops which can be modified)
    
    NMI_Handler     PROC
                    EXPORT  NMI_Handler               [WEAK]
                    B       .
                    ENDP
    HardFault_Handler\
                    PROC
                    EXPORT  HardFault_Handler         [WEAK]
                    B       .
                    ENDP
    MemManage_Handler\
                    PROC
                    EXPORT  MemManage_Handler         [WEAK]
                    B       .
                    ENDP
    BusFault_Handler\
                    PROC
                    EXPORT  BusFault_Handler          [WEAK]
                    B       .
                    ENDP
    UsageFault_Handler\
                    PROC
                    EXPORT  UsageFault_Handler        [WEAK]
                    B       .
                    ENDP
    SVC_Handler     PROC
                    EXPORT  SVC_Handler               [WEAK]
                    B       .
                    ENDP
    DebugMon_Handler\
                    PROC
                    EXPORT  DebugMon_Handler          [WEAK]
                    B       .
                    ENDP
    PendSV_Handler  PROC
                    EXPORT  PendSV_Handler            [WEAK]
                    B       .
                    ENDP
    SysTick_Handler PROC
                    EXPORT  SysTick_Handler           [WEAK]
                    B       .
                    ENDP
    
    Default_Handler PROC
    
                    EXPORT  WDT_IRQHandler            [WEAK]
                    EXPORT  TIMER0_IRQHandler         [WEAK]
                    EXPORT  TIMER1_IRQHandler         [WEAK]
                    EXPORT  TIMER2_IRQHandler         [WEAK]
                    EXPORT  TIMER3_IRQHandler         [WEAK]
                    EXPORT  UART0_IRQHandler          [WEAK]
                    EXPORT  UART1_IRQHandler          [WEAK]
                    EXPORT  UART2_IRQHandler          [WEAK]
                    EXPORT  UART3_IRQHandler          [WEAK]
                    EXPORT  PWM1_IRQHandler           [WEAK]
                    EXPORT  I2C0_IRQHandler           [WEAK]
                    EXPORT  I2C1_IRQHandler           [WEAK]
                    EXPORT  I2C2_IRQHandler           [WEAK]
                    EXPORT  SPI_IRQHandler            [WEAK]
                    EXPORT  SSP0_IRQHandler           [WEAK]
                    EXPORT  SSP1_IRQHandler           [WEAK]
                    EXPORT  PLL0_IRQHandler           [WEAK]
                    EXPORT  RTC_IRQHandler            [WEAK]
                    EXPORT  EINT0_IRQHandler          [WEAK]
                    EXPORT  EINT1_IRQHandler          [WEAK]
                    EXPORT  EINT2_IRQHandler          [WEAK]
                    EXPORT  EINT3_IRQHandler          [WEAK]
                    EXPORT  ADC_IRQHandler            [WEAK]
                    EXPORT  BOD_IRQHandler            [WEAK]
                    EXPORT  USB_IRQHandler            [WEAK]
                    EXPORT  CAN_IRQHandler            [WEAK]
                    EXPORT  DMA_IRQHandler            [WEAK]
                    EXPORT  I2S_IRQHandler            [WEAK]
                    EXPORT  ENET_IRQHandler           [WEAK]
                    EXPORT  RIT_IRQHandler            [WEAK]
                    EXPORT  MCPWM_IRQHandler          [WEAK]
                    EXPORT  QEI_IRQHandler            [WEAK]
                    EXPORT  PLL1_IRQHandler           [WEAK]
                    EXPORT  USBActivity_IRQHandler    [WEAK]
                    EXPORT  CANActivity_IRQHandler    [WEAK]
    
    WDT_IRQHandler
    TIMER0_IRQHandler
    TIMER1_IRQHandler
    TIMER2_IRQHandler
    TIMER3_IRQHandler
    UART0_IRQHandler
    UART1_IRQHandler
    UART2_IRQHandler
    UART3_IRQHandler
    PWM1_IRQHandler
    I2C0_IRQHandler
    I2C1_IRQHandler
    I2C2_IRQHandler
    SPI_IRQHandler
    SSP0_IRQHandler
    SSP1_IRQHandler
    PLL0_IRQHandler
    RTC_IRQHandler
    EINT0_IRQHandler
    EINT1_IRQHandler
    EINT2_IRQHandler
    EINT3_IRQHandler
    ADC_IRQHandler
    BOD_IRQHandler
    USB_IRQHandler
    CAN_IRQHandler
    DMA_IRQHandler
    I2S_IRQHandler
    ENET_IRQHandler
    RIT_IRQHandler
    MCPWM_IRQHandler
    QEI_IRQHandler
    PLL1_IRQHandler
    USBActivity_IRQHandler
    CANActivity_IRQHandler
    
                    B       .
    
                    ENDP
    
    
                    ALIGN
    
    
    ; User Initial Stack & Heap
    
                    IF      :DEF:__MICROLIB
    
                    EXPORT  __initial_sp
                    EXPORT  __heap_base
                    EXPORT  __heap_limit
    
                    ELSE
    
                    IMPORT  __use_two_region_memory
                    EXPORT  __user_initial_stackheap
    __user_initial_stackheap
    
                    LDR     R0, =  Heap_Mem
                    LDR     R1, =(Stack_Mem + Stack_Size)
                    LDR     R2, = (Heap_Mem +  Heap_Size)
                    LDR     R3, = Stack_Mem
                    BX      LR
    
                    ALIGN
    
                    ENDIF
    
    
                    END
    

    I played with the stack size according to:

    http://www.keil.com/pack/doc/mw/USB/html/usb_resource_requirements.html#usbd_res_req 

    I have a CDC (2 threads) and 4 threads totalling 6 * 512 = 3072 bytes but the behavior persists. 

    In 

    RTX_Conf_CM.c:

    ...
    #include "cmsis_os.h"
     
    
    /*----------------------------------------------------------------------------
     *      RTX User configuration part BEGIN
     *---------------------------------------------------------------------------*/
     
    //-------- <<< 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; initially 5
    #ifndef OS_TASKCNT
     #define OS_TASKCNT     5
    #endif
     
    //   <o>Default Thread stack size [bytes] <64-4096:8><#/4>
    //   <i> Defines default stack size for threads with osThreadDef stacksz = 0
    //   <i> Default: 200
    #ifndef OS_STKSIZE
     #define OS_STKSIZE     50      // this stack size value is in words
    #endif
     
    //   <o>Main Thread stack size [bytes] <64-32768:8><#/4>
    //   <i> Defines stack size for main thread.
    //   <i> Default: 200
    #ifndef OS_MAINSTKSIZE
     #define OS_MAINSTKSIZE 512     // this stack size value is in words
    #endif
     
    //   <o>Number of threads with user-provided stack size <0-250>
    //   <i> Defines the number of threads with user-provided stack size.
    //   <i> Default: 0
    #ifndef OS_PRIVCNT
     #define OS_PRIVCNT     2
    #endif
     
    //   <o>Total stack size [bytes] for threads with user-provided stack size <0-1048576:8><#/4>
    //   <i> Defines the combined stack size for threads with user-provided stack size.
    //   <i> Default: 0
    #ifndef OS_PRIVSTKSIZE
     #define OS_PRIVSTKSIZE 512       // this stack size value is in words
    #endif
     
    //   <q>Stack overflow checking
    //   <i> Enable stack overflow checks at thread switch.
    //   <i> Enabling this option increases slightly the execution time of a thread switch.
    #ifndef OS_STKCHECK
     #define OS_STKCHECK    1
    #endif
     
    //   <q>Stack usage watermark
    //   <i> Initialize thread stack with watermark pattern for analyzing stack usage (current/maximum) in System and Thread Viewer.
    //   <i> Enabling this option increases significantly the execution time of osThreadCreate.
    #ifndef OS_STKINIT
    #define OS_STKINIT      0
    #endif
     
    //   <o>Processor mode for thread execution 
    //     <0=> Unprivileged mode 
    //     <1=> Privileged mode
    //   <i> Default: Privileged mode
    #ifndef OS_RUNPRIV
     #define OS_RUNPRIV     1
    #endif
     
    // </h>
     
    // <h>RTX Kernel Timer Tick Configuration
    // ======================================
    //   <q> Use Cortex-M SysTick timer as RTX Kernel Timer
    //   <i> Cortex-M processors provide in most cases a SysTick timer that can be used as 
    //   <i> as time-base for RTX.
    #ifndef OS_SYSTICK
     #define OS_SYSTICK     1
    #endif
    //
    //   <o>RTOS Kernel Timer input clock frequency [Hz] <1-1000000000>
    //   <i> Defines the input frequency of the RTOS Kernel Timer.  
    //   <i> When the Cortex-M SysTick timer is used, the input clock 
    //   <i> is on most systems identical with the core clock.
    #ifndef OS_CLOCK
     #define OS_CLOCK       100000000
    #endif
     
    //   <o>RTX Timer tick interval value [us] <1-1000000>
    //   <i> The RTX Timer tick interval value is used to calculate timeout values.
    //   <i> When the Cortex-M SysTick timer is enabled, the value also configures the SysTick timer.
    //   <i> Default: 1000  (1ms)
    #ifndef OS_TICK
     #define OS_TICK        1000
    #endif
     
    // </h>
     
    // <h>System Configuration
    // =======================
    //
    // <e>Round-Robin Thread switching
    // ===============================
    //
    // <i> Enables Round-Robin Thread switching.
    #ifndef OS_ROBIN
     #define OS_ROBIN       1
    #endif
     
    //   <o>Round-Robin Timeout [ticks] <1-1000>
    //   <i> Defines how long a thread will execute before a thread switch.
    //   <i> Default: 5
    #ifndef OS_ROBINTOUT
     #define OS_ROBINTOUT   5
    #endif
     
    // </e>
     
    // <e>User Timers
    // ==============
    //   <i> Enables user Timers
    #ifndef OS_TIMERS
     #define OS_TIMERS      1
    #endif
     
    //   <o>Timer Thread Priority
    //                        <1=> Low
    //     <2=> Below Normal  <3=> Normal  <4=> Above Normal
    //                        <5=> High
    //                        <6=> Realtime (highest)
    //   <i> Defines priority for Timer Thread
    //   <i> Default: High
    #ifndef OS_TIMERPRIO
     #define OS_TIMERPRIO   5
    #endif
     
    //   <o>Timer Thread stack size [bytes] <64-4096:8><#/4>
    //   <i> Defines stack size for Timer thread.
    //   <i> Default: 200
    #ifndef OS_TIMERSTKSZ
     #define OS_TIMERSTKSZ  50     // this stack size value is in words
    #endif
     
    //   <o>Timer Callback Queue size <1-32>
    //   <i> Number of concurrent active timer callback functions.
    //   <i> Default: 4
    #ifndef OS_TIMERCBQS
     #define OS_TIMERCBQS   4
    #endif
     
    // </e>
     
    //   <o>ISR FIFO Queue size<4=>   4 entries  <8=>   8 entries
    //                         <12=> 12 entries  <16=> 16 entries
    //                         <24=> 24 entries  <32=> 32 entries
    //                         <48=> 48 entries  <64=> 64 entries
    //                         <96=> 96 entries
    //   <i> ISR functions store requests to this buffer,
    //   <i> when they are called from the interrupt handler.
    //   <i> Default: 16 entries
    #ifndef OS_FIFOSZ
     #define OS_FIFOSZ      16
    #endif
     
    // </h>
     
    //------------- <<< end of configuration section >>> -----------------------
     
    // Standard library system mutexes
    // ===============================
    //  Define max. number system mutexes that are used to protect 
    //  the arm standard runtime library. For microlib they are not used.
    #ifndef OS_MUTEXCNT
     #define OS_MUTEXCNT    8
    #endif
    
    ...

    5 is the max no. of threads, OS_STKSIZE is set to 50. I'm not exactly sure but do these conflict with the thread stack size?

    Do you happen to have any config files for USB + threaded apps lying around?