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?
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.
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:
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?