Download Micriµm µC/OS-II µC/USB µC/OS-View
Transcript
Micriµm Empowering Embedded Systems µC/OS-II µC/USB µC/OS-View for the NXP LPC2888 CPU (Using the Nohau LPC2800 Evaluation Board) Application Note AN-9888 www.Micrium.com Micriµm µC/OS-II, µC/OS-View and µC/USB for the NXP LPC2888 CPU Table Of Contents 1.00 1.01 1.02 Introduction Directories and Files IAR Embedded Workbench 2.00 2.01 2.02 Example Code Example Code, app.c Example Code, os_cfg.h 10 11 15 3.00 3.01 3.02 3.03 Board Support Package (BSP) IAR-Specific BSP Files BSP, bsp.c and bsp.h LCD Display Control & Interface Functions 16 16 16 21 4.00 4.01 4.02 4.03 4.04 μC/USB LPC2888 USB Considerations LPC2888 μC/USB Driver Details μC/USB-Bulk Example Enumeration μC/USB-Bulk Example 25 25 27 35 36 5.00 µC/OS-View 37 3 4 8 Licensing 39 References 39 Contacts 39 2 Micriµm µC/OS-II, µC/OS-View and µC/USB for the NXP LPC2888 CPU 1.00 Introduction This document shows example code for using µC/OS-II, µC/OS-II and µC/USB on a Nohau LPC2800 evaluation board, as shown in Figure 1, which employs NXP’s ARM7TDMI-based LPC2888 microcontroller. This flexible, full-featured device includes interfaces for high-speed USB 2.0, external SDRAM and Flash, MMC/SD memory cards, and various serial interfaces. In addition to the processor’s internal memory—1 MB Flash, 64 kB SRAM, and 32 kB ROM—the Nohau board is populated with one 128 Mb external SDRAM chip, one 64Mb external Flash chip (with the capability for another to be inserted), and a MMC/SD memory card slot. Uniquely, this processor may be powered from a single 1.5-volt AA battery, and though the Nohau board includes a battery holder and jumpers to select this as the power supply, a more usual source, a 5-volt DC adapter, was used as the power supply for all runs. The appropriate jumper settings are shown in Figure 1-2 where the notation ( ) superimposed on a jumper location indicates that the two left pins will be connected. Note that the two left pins are not necessarily pins 1 and 2, since pin 1 is designated as the pin beside the white triangle (. ). LCD Display MMC/SD Card ADC1 USB Port RS-232 Push button switches 20-pin J-Tag User LED 5V DC Power Figure 1-1, Nohau LPC2800 board 3 Micriµm µC/OS-II, µC/OS-View and µC/USB for the NXP LPC2888 CPU JP3: 2-3 JP4: 2-3 JP5: 2-3 JP20: 1-2 JP21: 2-3 JP22: 2-3 Figure 1.2, Jumper settings for 5V DC supply 1.01 Directories and Files The code and documentation of the port are placed in directories in accordance with “AN-2002, µC/OS-II Directory Structure”. µC/OS-II: \Micrium\Software\uCOS-II\Source This directory contains the processor independent code for µC/OS-II. The version used was 2.83. \Micrium\Software\uCOS-II\Ports\ARM\Generic\IAR This directory contains the standard processor-specific files for the generic µC/OS-II ARM port assuming the IAR toolchain. These files could easily be modified to work with other toolchains (i.e. compiler/assembler/linker/locator/debugger); however, you would 4 Micriµm µC/OS-II, µC/OS-View and µC/USB for the NXP LPC2888 CPU place the modified files in a different directory. Specifically, this directory contains the following files: • os_cpu.h • os_cpu_a.asm • os_cpu_c.c • os_dcc.c • os_dbg.c is included to provide additional information to Kernel Aware debuggers like IAR’s C-Spy. With this port, you can use µC/OS-II in either ARM or Thumb mode. Thumb mode, which drastically reduces the size of the code, was used in this example, but compiler settings may be switched to generate ARM-mode code without needing to change either the port or the application code. The ARM/Thumb port is fully described in application note AN-1014 which is available from the Micrium web site. µC/OS-View: \Micrium\Software\uCOSView\Source This directory contains the processor independent code for µC/OS-View. The version used was 1.20. This directory contains the following files: • os_view.c • os_view.h \Micrium\Software\uCOSView\Ports\ARM7\LPC2888\IAR This directory contains the LPC2888-specific port for µC/OS-View: • os_viewc.c • os_viewc.h µC/USB: \Micrium\Software\uC-USB-MSD\Firmware\USBBulk This directory contains the source code for µC/USB-Bulk: • USB.h • USB_Main.c • USB_Private.h • USB_Read.c • USB_Setup.c • USB_Write.c \Micrium\Software\uC-USB-MSD\Firmware\USBBulk USB_X_uCOS-II.c, the µC/OS-II port for µC/USB-Bulk, is located in this directory. 5 Micriµm µC/OS-II, µC/OS-View and µC/USB for the NXP LPC2888 CPU \Micrium\Software\uC-USB-Driver\LPC2888 The USB_hw.c file in this directory is the LPC2888-specific port for µC/USB-Bulk. \Micrium\Software\EvalBoards\NXP\LPC2888\IAR\OS-View-USB µC/USB-Bulk expects two configuration files: • USB_Descriptors.c provides definitions of the USB descriptors which will be transmitted to the host during enumeration. • USB_Conf.h contains defines used to target the USB descriptors to the appropriate driver or transmission protocol. Application Code: \Micrium\Software\EvalBoards\NXP\LPC2888\IAR\OS-View-USB This directory contains the source code for the example application, composed of the following files: • app.c contains the test code for the example application including the functions that start µC/OS-II, register tasks with the operating system, and update the user interface (the LEDs and LCD). The initialization functions of supplementary installed modules, µC/OS-View and µC/USB, are called from this file as well. app_cfg.h is a configuration file specifying stack sizes and priorities for all tasks and #defines for important global application constants. • includes.h is a master include file used by the application. • os_cfg.h is the µC/OS-II configuration file. • LPC2888-OS-View-USB.* are the IAR Embedded Workbench project files. \Micrium\Software\EvalBoards\NXP\LPC2888\IAR\BSP This directory contains the Board Support Package for the Nohau LPC2800 board: • bsp.c contains the board support package which initializes critical processor functions (e.g., the clock generation unit) and provides support for peripherals such as the LCD display and the LED on the board. bsp.h contains prototypes for functions that may be called by the user. • bsp_exceptions.c contains functions and variables for initializing interrupts, installing handlers, and directing interrupts to the appropriate handlers. The exception handler which will be called by the µC/OS-II ARM port when the OS handles an interrupt is in this file. • LPC2888_RAM.xcl is an IAR linker file which contains information about the placement of data and code segments in the processor’s memory map. The data, code, and execution stacks are all mapped to RAM. • LPC2888_RAM.mac contains instructions that are executed prior to loading code onto the processor. In this case, the processor is instructed to boot from RAM when a warm reset occurs. • lpc2xxx_startup.s79 \Micrium\Software\uC-CPU\ARM\IAR This directory contains processor-specific code intended to be used with the IAR compiler for ARM processors. 6 Micriµm µC/OS-II, µC/OS-View and µC/USB for the NXP LPC2888 CPU • cpu_def.h, which is located directly in \Micrium\Software\uC-CPU, declares #define constants for CPU alignment, endianness, and other generic declarations. • cpu.h defines the Micriµm portable data types for 8, 16, and 32-bit signed and unsigned numbers (such as CPU_INT16U, which is a 16-bit unsigned type). These allow code to be independent of processor and compiler word size definitions. • cpu_a.s contains generic assembly code for ARM7 or ARM9 processors which is used to enable and disable interrupts within the operating system. This code is called from C with OS_ENTER_CRITICAL() and OS_EXIT_CRITICAL(). \Micrium\Software\EvalBoards\NXP\LPC2888\Doc This directory is the directory that contains the documentation for the Nohau LPC2800 board test code. 7 Micriµm µC/OS-II, µC/OS-View and µC/USB for the NXP LPC2888 CPU 1.02 IAR Embedded Workbench We used the IAR Embedded Workbench (EW) V4.40a to test the example. Of course, µC/OS-II can be used with other tools. Figure 1-3 shows the project configuration tree in the EW. Figure 1-3, IAR EW Project Configuration The test code works either in ARM or Thumb mode. In fact, if you switch between ARM and Thumb Processor Mode in the settings dialog box (see Figure 1-4) and rebuild the project, your code should run just as well. By selecting ‘Thumb’ and choosing to generate ‘Interwork’ code, you can mix ARM and Thumb code in your application. 8 Micriµm µC/OS-II, µC/OS-View and µC/USB for the NXP LPC2888 CPU Figure 1-4, IAR EWARM Options The IAR Embedded Workbench works with Micrium’s µC/OS-II Kernel Awareness Plug-In which allows you to examine µC/OS-II kernel objects in tabular format when running the IAR C-Spy debugger. Figure 1-5 shows all the tasks created in the example. For each task, you can see where the current stack pointer is pointing, how much stack space is being used, and other properties. The task names (which you may assign) are also listed. The Kernel Awareness Plug-In provides a number of other useful information about µC/OS-II (semaphore list, mailbox list, queue list, etc.). Figure 1-5, µC/OS-II Kernel Awareness in C-Spy, Task List 9 Micriµm µC/OS-II, µC/OS-View and µC/USB for the NXP LPC2888 CPU 2.00 Example Code When started, the example code displays on the LCD screen a summary of the current µC/OS-II state (as shown in Figure 2-1). This summary includes the tick rate (i.e., number of ticks per second), the CPU usage and clock speed, and two cumulative variables representing the total number of ticks and the total number of context switches that have occurred since the application was started. Figure 2-1, μC/OS-II system information Figure 2-2, Screen, Scrolled The push buttons, which are polled 10 times per second, control the vertical “scrolling” of the LCD. When push button #2 (labeled GPIO_3 on the board) is pushed, the text moves up and wraps around to the bottom of the screen. Push button #1 has the opposite effect: when pressed, the text moves down, toward the bottom of the screen, and wraps around to the top. The information on the screen is refreshed five times per second. 10 Micriµm µC/OS-II, µC/OS-View and µC/USB for the NXP LPC2888 CPU The left-hand potentiometer, immediately beneath the LCD—marked ADC1—can be used to control the brightness of the display. If the knob is turned clockwise, then the display becomes bright; when turned counterclockwise, the display dims. If the display is initially too dim or bright to read, turn the knob to adjust the setting. A simple demonstration of µC/USB-Bulk is provided as well. After initialization, this example alternately reads from and writes to the USB port, incrementing the data byte between the read and the write. The Nohau LPC2800 board resets when the USB cable is plugged in during operation, moves through its boot sequence, and loads data from Flash. Because this overwrites the code in RAM (whereto the data from the example project is written), the USB cable should be inserted prior to programming the LPC2888. 2.01 Example Code, app.c A limited set of the LPC2888 capabilities are exhibited by the application code in app.c. A few tasks are created, one of which is dedicated to the user interface and update of the LCD. Another, after initializing µC/USB-Bulk, alternately reads and writes from the USB port. However, the power and convenience of both the µC/OS-II Kernel Awareness plug-in for C-Spy and µC/OS-View are amply demonstrated with this small application. As with most C programs, we assume that the compiler startup code brings the CPU to execute main(). If you design an embedded application running out of Flash, we expect that you will properly initialize the CPU (clocks, power management, memory management, chip selects, etc.) and have your code call main(). Listing 2-1, main() void { main (void) CPU_INT08U (1) err; BSP_IntDisAll(); (2) OSInit(); (3) OSTaskCreateExt(AppTask_Start, (4) (void *)0, (OS_STK *)&AppTask_StartStk[APP_TASK_START_STK_SIZE - 1], APP_TASK_START_PRIO, APP_TASK_START_PRIO, (OS_STK *)&AppTask_StartStk[0], APP_TASK_START_STK_SIZE, (void *)0, OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR); #if OS_TASK_NAME_SIZE > 13 OSTaskNameSet(APP_TASK_START_PRIO, "Start Task", &err); #endif OSStart(); (6) } L2-1(1) (5) As with most C applications, the code starts in main(). 11 Micriµm µC/OS-II, µC/OS-View and µC/USB for the NXP LPC2888 CPU L2-1(2) All interrupts are disabled to make sure the application does not get interrupted until it is fully initialized. L2-1(3) As with all µC/OS-II applications, OSInit() must be called before creating a task or any other kernel object. L2-1(4) We then create at least one task (in this case, using OSTaskCreateExt() to obtain additional information about your task). µC/OS-II creates either one or two internal tasks in OSInit(). µC/OS-II always creates an idle task, OS_TaskIdle(), and will create a statistics task, OS_TaskStat() if you set OS_TASK_STAT_EN to 1 in OS_CFG. L2-1(5) As of V2.6x, you can now name µC/OS-II tasks (and other kernel objects) and display task names at run-time or with a debugger. In this case, we name our first task as well as the two internal µC/OS-II tasks. Because C-Spy can work with the Kernel Awareness Plug-In available from Micrium, task names can be displayed during debugging. L2-1(6) Finally, µC/OS-II is started by calling OSStart(). µC/OS-II will then begin executing AppTask_Start() since that is the highest priority task created (both OS_TaskStat() and OS_TaskIdle() have lower priorities). Listing 2-2, AppStartTask() static void AppStartTask (void *p_arg) { CPU_INT08U i; CPU_INT08U j; BOOLEAN status1; BOOLEAN status2; (void)p_arg; BSP_Init(); (1) #if OS_TASK_STAT_EN > 0 OSStatInit(); #endif (2) #if OS_VIEW_MODULE > 0 OSView_Init(38400); OSView_TerminalRxSetCallback(AppTerminalRx); OSView_RxIntEn(); #endif #if uC_USB_BULK_MODULE > 0 AppInit_USB(); #endif (3) (4) i = 0; j = 0; AppPrintPage(); adc_old = (ADC_GetStatus(1) >> 5) + 32; while (DEF_TRUE) { OSTimeDly(OS_TICKS_PER_SEC / 10); j = (j + 1) % 2; if (j == 0) { AppUpdatePage(); } (5) (6) (7) status1 = PB_GetStatus(1); 12 Micriµm µC/OS-II, µC/OS-View and µC/USB for the NXP LPC2888 CPU status2 = PB_GetStatus(2); if ((status1 == DEF_TRUE) && (status2 == DEF_FALSE)) { i = (i + 2) % 64; LCD_SetStartLine(i); LED_Toggle(1); } else if ((status1 == DEF_FALSE) && status2 == DEF_TRUE) { i = 63 - (65 - i) % 64; LCD_SetStartLine(i); LED_Toggle(1); } adc_new = (ADC_GetStatus(1) >> 5) + 32; if (adc_new != adc_old) { LCD_SetBrightness(adc_new); adc_old = adc_new; } (8) (9) (10) } } L2-2(1) BSP_Init() initializes the Board Support Package—the I/Os, the tick interrupt, etc. (See Section 3.0 for details.) L2-2(2) OSStatInit() is initializes µC/OS-II’s statistic task. This only occurs if you enable the statistics task by setting OS_TASK_STAT_EN to 1 in OS_CFG.H. The statistics task measures overall CPU usage (expressed as a percentage) and also performs stack checking for all the tasks that have been created with OSTaskCreateExt() with the stack checking option set. L2-2(3) OSView_Init() initializes the µC/ OS-View module, including the UART interface, for which reason the baud rate of the RS-232C port connected to the Windows view is specified as an argument. If you did not purchase µC/OS-View, please disable it according to the instructions contained in Section 5.00. L2-2(4) AppInit_USB() creates a new task which will initialize the µC/USB-Bulk and perform a simple test of the communications. See Listing 2-3. L2-2(5) The initial text is printed to the LCD. Also, in the next line, the initial brightness of the display is set using the current value of ADC1, the left-hand variable resistor. L2-2(6) Any task managed by µC/OS-II must either enter an infinite loop ‘waiting’ for some event to occur or terminate itself. In an infinite loop, the task polls the two user push buttons, scrolling the screen if only one is pressed, and updates the LCD controller RAM intermittently. L2-2(7) Five times per second the data in the LCD RAM is updated. L2-2(8) If push button #2 is pressed, then the text on the screen scrolls upwards, wrapping around to the bottom of the screen. L2-2(9) If push button #1 is pressed, then the text on the screen scrolls downwards, wrapping around to the top of the screen. L2-2(10) The current value of ADC1 is read and if this value is different than the old value, the brightness of the LCD is changed accordingly. Due to the processing time necessary for the A/D, the state of the display may lag behind the rotation of the ADC1 knob. 13 Micriµm µC/OS-II, µC/OS-View and µC/USB for the NXP LPC2888 CPU Listing 2-3, AppTaskUSB() static void AppTaskUSB(void *p_arg) { CPU_INT08U c; (void)p_arg; USB_Init(); USB_X_Init(); (1) (2) while (USB_IsConfigured() == 0) { USB_X_Delay(150); LED_Toggle(1); } (3) LED_Toggle(1); USB_X_Delay(500); LED_Toggle(1); USB_X_Delay(500); LED_Toggle(1); USB_X_Delay(500); LED_Toggle(1); USB_X_Delay(500); (4) while (DEF_TRUE) { USB_Read(&c, 1); (5) LED_Toggle(1); USB_X_Delay(50); c++; USB_Write(&c, 1); } } This task is created by AppInit_USB(), called from AppStartTask(), to perform a simple test of µC/USB-Bulk after initializing the stack and the LPC2888 USB controller. For further information about the LPC2888 port, please refer to Section 4.00. L2-3(1) USB_Init() initializes the LPC2888 USB controller (see Section 4.00 for more details). L2-3(2) USB_X_Init() initializes the structures, such as semaphores, provided by µC/OSII for µC/USB-Bulk. L2-3(3) While the USB configuration is incomplete, the task is delayed and a LED is toggled between calls to USB_IsConfigured() to determine the current configuration status. L2-3(4) The LED is toggled slowly four times to indicate that the USB controller is now configured. L2-3(5) Within this infinite loop, a byte is read from the USB stack, incremented, and then written back. Of course, this test will only work with a very specific application running on the host, an example of which is provided directly under the Micriµm directory in the zip file containing this document. 14 Micriµm µC/OS-II, µC/OS-View and µC/USB for the NXP LPC2888 CPU 2.02 Example Code, os_cfg.h This file is used to configure µC/OS-II. Among the approximately 60 #defines in this file are included variables defining the maximum number of tasks that your application can have, which services will be enabled (semaphores, mailboxes, queues, etc.), and the size of the idle and statistic task. Each entry is commented and additional information about the purpose of each #define can be found in µC/OS-II, the Real-Time Kernel by Jean Labrosse. os_cfg.h assumes you have µC/OS-II V2.83 or higher. 15 Micriµm µC/OS-II, µC/OS-View and µC/USB for the NXP LPC2888 CPU 3.00 Board Support Package (BSP) The Board Support Package (BSP) provides functions to encapsulate common I/O access functions and make porting your application code easier. Essentially, these files are the interface between the application and the Nohau LCP2800 board. Though one file, bsp.c, contains some functions which are intended to be called direcly by the user (all of which are prototyped in bsp.h), the other files serve the compiler (as with lpc2xxx_cstartup.s79). 3.01 IAR-Specific BSP Files The BSP includes three files intended specifically for use with IAR tools: LPC2888_RAM.xcl, LPC2888_RAM.mac, and lpc2xxx_cstartup.s79. These serve to define the memory map and initialize the processor prior to loading or executing code. If the example application is to be used with other toolchains, the services provided by these files must be replicated as appropriate. Before the processor memories can be programmed, the compiler must know where code and data should be placed. To accomplish this, IAR requires a linker command file, such as LPC2888_RAM.xcl, that provides directives to accomplish this. All code, data, and stack and heap segments are placed in the 64kB internal RAM between 0x0000400040 and 0x0040FFFF. The first 64 bytes of RAM are reserved for the exception vector table. The CSpy macro file LPC2888_RAM.mac declares routines which will be executed prior to loading code on the processor and after a processor reset. In lpc2xxx_cstartup.s79 is code which will be executed prior to calling main. One important inclusion is the specification of the exception vector table (as required for ARM cores) and the setup of various exception stacks. After executing, this function branches to the IAR-specific ?main function, in which the processor is further readied for entering application code. 3.02 BSP, bsp.c and bsp.h We will not be discussing every aspect of the BSP but only cover topics that require special attention. bsp.c contains I/O control code as well as the code for handling the µC/OS-II tick interrupt. Your application code needs to call BSP_Init() in order to properly initialize the services provided by the file. 16 Micriµm µC/OS-II, µC/OS-View and µC/USB for the NXP LPC2888 CPU Listing 3-1, BSP_Init() void { BSP_Init (void) BSP_Cache_Init(); BSP_CGU_Init(); BSP_Int_Init(); Tmr_TickInit(); (1) (2) (3) (4) LCD_Init(); LCD_ClrScr(); (5) PB_Init(); } L3-1(1) This function maps the bottom portion of RAM—where the exception vectors are located by specification within the linker command file—to 0x00000000, where ARMs expect the exception vectors to be located. See Listing 3-2 for details. L3-1(2) The clock generation unit and the clocks used for peripheral chip functions are initialized. See Listing 3-3 for details. L3-1(3) We then call a function which is responsible for initializing the Interrupt Controller. See Listing 3-4 for details. L3-1(4) The µC/OS-II tick interrupt source is then initialized. See Listing 3-5 for details. L3-1(5) The LCD on the evaluation board is then initialized. See Listing 3-6 for details. Listing 3-2, BSP_Cache_Init() static void BSP_Cache_Init (void) { CACHE_SETTINGS = 0x00000001; CACHE_SETTINGS = 0x00000000; (1) (2) while ((CACHE_RST_STAT) & 0x00000001) { ; } (3) CACHE_PAGE_CTRL = 0x00000001; ADDRESS_PAGE_0 = (0x400000 >> 21); CACHE_SETTINGS = 0x00000016; (4) (5) (6) } L3-2(1) The cache controller is reset. L3-2(2) The reset bit is de-asserted. L3-2(3) CACHE_RST_STAT is polled to determine whether the cache reset process, which takes 128 clock cycles, has completed. L3-2(4) Caching is enabled for page 0, which covers the range between 0x00000000 and 0x001FFFFF. L3-2(5) The address range covered by page 0, 0x00000000 to 0x001FFFFF, will become the virtual address range for the the 2 kB following 0x400000, which is the lower part of RAM in the LPC2888. Thus, if the address location 0x0000001C is accessed, the address 0x0040001C will be loaded. 17 Micriµm µC/OS-II, µC/OS-View and µC/USB for the NXP LPC2888 CPU L3-2(6) Caching is enabled for both data and instructions. Listing 3-3, BSP_CGU_Init() static void { LPPDN LPFIN LPMSEL LPPSEL LPPDN BSP_CGU_Init (void) = = = = = 0x00000001; 0x00000001; 0x00000003; 0x00000001; 0x00000000; (1) (2) (3) (4) (5) while (LPLOCK == 0x00000000) { ; } (6) SYSFSR1 SYSSCR APB0FSR1 APB0SCR APB1FSR1 APB1SCR UARTFSR1 UARTSCR (7) = = = = = = = = CGU_FSR_MAIN_PLL; CGU_SCR_ENF1; CGU_FSR_MAIN_PLL; CGU_SCR_ENF1; CGU_FSR_MAIN_PLL; CGU_SCR_ENF1; CGU_FSR_MAIN_PLL; CGU_SCR_ENF1; SYSFDCR1 &= ~CGU_FDCR_FDRUN; (8) SYSFDCR1 (9) = ((BSP_SYSFSR2_MSUB << 11) | (BSP_SYSFSR2_MADD << 3) | CGU_FDCR_FDSTRCH | CGU_FDCR_FDRES); SYSFDCR1 &= ~CGU_FDCR_FDRES; (10) SYSFDCR1 |= CGU_FDCR_FDRUN; (11) AHB0ESR USBESR0 LCDESR1 LCDESR0 = = = = CGU_ESR_SSCLOCK; CGU_ESR_SSCLOCK; CGU_ESR_FD1; CGU_ESR_SSCLOCK; (12) T0ESR T1ESR = CGU_ESR_SSCLOCK; = CGU_ESR_SSCLOCK; (13) UARTESR1 = CGU_ESR_SSCLOCK; (14) SYSBCR = CGU_BCR_FDRUN; (15) } L3-3(1) The main PLL is powered down. L3-3(2) The main oscillator (12 MHz) is selected as the PLL’s input clock. L3-3(3) The output clock from the PLL will be CPLL = (LPMSEL + 1) x COSC = 48 MHz L3-3(4) The CCO frequency, which should be between 160 MHz and 320 MHz, is CCO = COSC x 2LPPSEL + 1 = 48 MHz x 4 = 192 MHz. L3-3(5) The main PLL is powered up. L3-3(6) LPLOCK is polled until it holds a non-zero value, which indicates that the PLL has locked. L3-3(7) The clocks are routed to devices via a hierarchical scheme. These four lines assign the PLL output to four selection stages: the main system stage, the APB0 stage, the 18 Micriµm µC/OS-II, µC/OS-View and µC/USB for the NXP LPC2888 CPU APB1 stage, and the UART stage. Later, in L3-3(12), the spreading stages will distribute these (and clocks from the fractional dividers) to the various clocks used on the processor. L3-3(8) The SYS selection stage’s fractional divider number 1 is stopped. L3-3(9) The SYS selection stage’s fractional divider number 1 is setup. fractional divider is equal to The output of the C PLL × n C PLL × − M SUB = so M ADD = m − n , M SUB = − n m M ADD − M SUB The output of the clock, which will be the LCD clock, should be equal to 6 MHz; therefore, n = 16 = 0 x10 and m = 128 = 0 x80 is a solution. The proper values of M ADD and M SUB will be 0x70 and 0x10 , respectively. L3-3(10) The reset bit of the SYS selection stage’s fractional divider number 1 is toggled off. L3-3(11) The SYS selection stage’s fractional divider number 1 is restarted. L3-3(12) The SYS selection stage clock is chosen as clock for the USB and LCD PCLK selection stages. However, the output of SYS’s fractional divider number 1 is chosen as the LCD bus clock. L3-3(13) The APB1 selection stage clock is chosen as the clock for the timer selection stages. L3-3(14) The UART selection stage clock is chosen asthe clock for the UART selection stage. Listing 3-4, BSP_Int_Init() static void BSP_Int_Init (void) { CGU_INT16U i; for (i = 1; i < 29; i++) { Int_Table[i] = (CGU_INT32U)BSP_Dummy_ISR_Handler; } (1) } L3-4(1) The variable, Int_Table, is an array declared in bsp.c to hold the addresses of the ISR handlers. The LPC2888 does not have registers to hold these values. Instead, the LPC2888 expects these to be stored in memory and provides a register, INT_VECTOR0, that may be loaded with the base address of a table in memory for such a purpose. We chose an alternative approach, merely instantiating an array and, in this function, initializing each ISR address to that of a dummy routine. As you install other interrupts for your application, some of these locations will be replaced by your own interrupt handlers. 19 Micriµm µC/OS-II, µC/OS-View and µC/USB for the NXP LPC2888 CPU Listing 3-5, Tmr_TickInit() static void Tmr_TickInit (void) { CGU_INT32U clk_freq; INT_REQ5 = ((1 << 27) | (1 << 26) | (1 << 16) | (1 << 28) | 0x1); Int_Table[5] /* /* /* /* /* Target is stored in bit 8 Enable is stored in bit 16 Enable the interrupt Value in 3:0 indicates the priority Set priority to 1 = (CPU_INT32U)Tmr_TickISR_Handler; */ */ */ */ */ (1) (2) clk_freq = BSP_CPU_ClkFreq(); Tmr_ReloadCnts = (clk_freq * 1000) / OS_TICKS_PER_SEC ; (3) T0CTRL T0LOAD T0CTRL (4) (5) = 0; = Tmr_ReloadCnts; = 0xC0; } L3-5(1) The timer interrupt is enabled, a priority (which could be used by an IRQ handler) is established, and the interrupt is set to trigger an IRQ rather than a FIQ. L3-5(2) The tick ISR handler location is stored in the Int_Table array (see Listing 3-3 for more information). L3-5(3) The timer reload value is calculated. L3-5(4) The LPC2888 timers are count-down timers that trigger an interrupt when reaching zero and, optionally, can be loaded with the value specified in the T0LOAD register. L3-5(5) The timer is configured to reload with the value in T0LOAD and is enabled. Listing 3-6, LCD_Init() static void { LCDCTRL LCD_Init (void) = 0x4000; (1) LCD_WrCmd(LCD_RESET_DISPLAY ); LCD_WrCmd(LCD_BIAS_SET_1_9 ); LCD_WrCmd(LCD_ADC_SELECT_REVERSE ); LCD_WrCmd(LCD_COMMON_OUTPUT_NORMAL ); LCD_WrCmd(LCD_V5_RESISTOR_RATIO ); LCD_WrCmd(LCD_ELECTRONIC_VOLUME_SET ); LCD_WrCmd(LCD_ELECTRONIC_VOLUME_INIT); LCD_WrCmd(LCD_POWER_CONTROL_SET | LCD_VOLTAGE_REGULATOR | LCD_VOLTAGE_FOLLOWER | LCD_BOOSTER_CIRCUIT ); LCD_WrCmd(LCD_DISPLAY_REVERSE ); LCD_WrCmd(LCD_DISPLAY_ON ); (2) } L3-6(1) The LCD chip select pin, LCS, is programmed to be low-active. L3-6(2) A series of commands are transmitted to the LCD controller specifying the hardware setup. After calling LCD_Init(), strings and characters can be written to the display using the functions LCD_DispStr() and LCD_DispChar(). These interface functions are described in section 3.1. 20 Micriµm µC/OS-II, µC/OS-View and µC/USB for the NXP LPC2888 CPU 3.03 LCD Display Control & Interface Functions The LCD display used on the Nohau LPC2800 evaluation board is controlled with an Epson S1D15605-series LCD driver. Unlike the Hitachi HD44780-compatible character-driven drivers supported by µC/LCD, the Epson driver is pixel-driven and must be sent not a character’s ASCII representation, but its dot-matrix representation. The BSP contains functions that define a character-driven programming interface for the module; however, a more extensive set of display functions, allowing individual pixels to be toggled or lines to be drawn, could be implemented. The LPC2888 includes an LCD interface compatible with 8-bit data buses such as the Intel 8080 or the Motorola 6800. By using this interface, control lines between the LCD and the processor are automatically set or cleared, and data or commands written to the appropriate register are automatically placed into a FIFO and routed to the data bus.. That the Epson S1D115605 is compatible with this interface greatly simplifies the code. The Epson S1D115605 contains on-board RAM sufficient for storing the pixel data for the 65 pixel rows by 132 pixel columns of the screen. A write to the controller modifies not the LCD output (which, of course, will change when updated) but the information in the RAM. This level of abstraction allows for additional flexibility, in several ways: 1) The “start line” is modifiable. The row of data displayed topmost on the screen may be set between 0 and 63, a functionality which may be accessed using LCD_SetStartLine() (see Listing 3-11). When performed dynamically, a “scrolling” effect may be achieved, as is demonstrated in the LPC2888 sample application, with almost no processor usage and little programming effort. 2) The display may be reversed. Without rewriting data to the S1D115605 RAM, the lit/unlit status of all LCD pixels may be reversed by writing a certain command to the display. 3) Read/modify/write cycles are possible. The RAM may be read and a modified version written back. If a specific set of sequential columns in a page need to be accessed and changed repeatedly—as for a blinking cursor or character, for example—the load on the S1D115605’s processing unit may be decreased with a special command sequence. After an initial command to enter read/modify/write mode, only writes will cause the accessed column to increment. When this mode is no longer required, an end command is sent to the controller, and the column position is restored to the location when the mode was entered. The character-driven user interface is comprised of four functions: LCD_DispChar() LCD_DispStr() LCD_DispClrLine() LCD_ClrScr() The first two functions store characters and strings, respectively, at specified locations Epson controller’s RAM. The last two allow the entire contents and a single line controller’s RAM, respectively, to be cleared (meaning, to be set all pixels LCD_DispChar() is presented in Listing 3-7, and LCD_DispClrLine() is presented 3-8. on the of the “off”). Listing Additionally, three functions are called by the interface functions to perform lower-level actions: 21 Micriµm µC/OS-II, µC/OS-View and µC/USB for the NXP LPC2888 CPU LCD_WrCmd() LCD_WrData() LCD_SetBrightness() LCD_SetPosition() The first two functions LCD_WrCmd() and LCD_WrData(), write a command or a byte of data to the driver (see Listing 3-10). The third function, LCD_SetBrightness(), sets the brightness of the display to one of the 64 possible levels, as specified by its argument. The forth function, LCD_SetPosition(), sets the position of the RAM to which data will be written (see Listing 39). Listing 3-6, LCD_DispChar() void { LCD_DispChar (CPU_INT08U line, CPU_INT08U col, CPU_INT08U c) CPU_INT08U i; if (col < BSP_LCD_CHARACTERS_PER_LINE && line < BSP_LCD_NUMBER_OF_LINES) { LCD_SetPosition(line, col); for (i = 0; i < 8; i++) { LCD_WrData(BSP_LCD_Charset[c-32][i]); } (1) (2) (3) } } L3-7(1) The validity of the function arguments, col and line, is checked. L3-7(2) The display position is set (see Listing 3-8). L3-7(3) A “font” is defined in bsp.c as the double-subscripted array BSP_LCD_Charset. Each row in the array specifies a certain character, and each character is itself a list of eight unsigned eight-bit integers specifying the eight columns in the character’s dot-matrix representation (as shown in Figure 3-1 for ASCII character 0x40, “@”). The integer 32 is subtracted from the c, the ASCII character code, because the first row of the table defines character 0x20 (or 32 in decimal), the space. (See Listing 39 for a description of LCD_WrData()). 22 Micriµm µC/OS-II, µC/OS-View and µC/USB for the NXP LPC2888 CPU Program Reference BSP_LCD_Charset[64][0] BSP_LCD_Charset[64][1] BSP_LCD_Charset[64][2] BSP_LCD_Charset[64][3] BSP_LCD_Charset[64][4] BSP_LCD_Charset[64][5] BSP_LCD_Charset[64][6] BSP_LCD_Charset[64][7] Hexadecimal Binary {0x00, 0x00, 0x00, 0x32, 0x49, 0x79, 0x41, 0x3E} 00000000 00000000 00000000 00110010 01001001 01111001 01000001 00111110 Character Output Figure 3-1. Coding of ASCII Character 0x40, “@” Listing 3-8, LCD_DispClrLine() void { LCD_DispClrLine (CPU_INT08U line) CPU_INT08U c_pos; CPU_INT08U i; if (line < BSP_LCD_NUMBER_OF_LINES) { LCD_SetPosition(line, 0); for (c_pos = 0; c_pos < BSP_LCD_CHARACTERS_PER_LINE; c_pos++) { for (i = 0; i < 8; i++) { LCD_WrData(BSP_LCD_Charset[0][i]); } } } (1) (2) (3) } L3-8(1) The validity of the function argument, line, is checked. L3-8(2) The display position is set (see Listing 3-8). L3-8(3) A space character is written to the position occupied by each of the characters in the line. LCD_ClrScr() loops through each line of the display, and for each line performs the same operation LCD_DispClrLine() performs for its argument—writing space characters to each character position. Listing 3-9, LCD_SetPosition() static void LCD_SetPosition (CPU_INT08U line, CPU_INT08U col) { CPU_INT08U nibble_upper; CPU_INT08U nibble_lower; nibble_upper = (col & 0x1E) >> 1; nibble_lower = (col & 0x01) << 3; (1) LCD_WrCmd(LCD_PAGE_ADDRESS_SET + line ); (2) 23 Micriµm µC/OS-II, µC/OS-View and µC/USB for the NXP LPC2888 CPU LCD_WrCmd(LCD_COLUMN_ADDRESS_UPPER_BIT_SET | nibble_upper); (3) LCD_WrCmd(LCD_COLUMN_ADDRESS_LOWER_BIT_SET | nibble_lower); } L3-9(1) The col argument passed to LCD_SetPosition is the character column on the display; however, the actual pixel column must be passed to the LCD driver. The pixel column is eight times the character column (there being eight columns of pixels in each character), and the upper and lower halves of the value must be passed in separate commands. This line and the next shift col left by three bits and extract the upper four and lower four bits, respectively. L3-9(2) The LCD driver sets the “start line”, or the line in the LCD controller’s RAM which will be the top line on the LCD display. L3-9(3) The desired page address of the display is sent to the driver. The RAM of the driver is divided into eight pages, each of which is eight pixels high; conveniently, this is the height of the font we defined. The page address coincides, consequently, with the line number. L3-9(4) The upper and lower halves of the pixel column are passed to the LCD driver. Listing 3-10, LCD_WrData() static void LCD_WrData (INT8U data) { CPU_INT32U status; status = (LCDSTAT >> 5) & 0x1F; while (status >= 0x0E) { status = (LCDSTAT >> 5) & 0x1F; } (1) (2) LCDDBYTE = data; (3) } L3-10(1) The number of bytes currently in the output FIFO is extracted from the LCDSTAT register value. L3-10(2) The function waits until the number of bytes in the output FIFO (which can hold only 16 bytes) no longer exceeds 13. L3-10(3) The data passed to the function is placed into the LCDDBYTE register. The function LCD_WrCmd(), which is used to write commands to the display, differs only by writing its argument to the byte instruction register, LCDIBYTE. Listing 3-11, LCD_SetStartLine() void { LCD_SetStartLine(CPU_INT08U line) LCD_WrCmd(LCD_START_LINE_SET + (line & 0x3F)); (1) } L3-11(1) The LCD driver sets the “start line”, or the line of data in the LCD controller’s RAM which will be the top line on the LCD display. 24 Micriµm µC/OS-II, µC/OS-View and µC/USB for the NXP LPC2888 CPU 4.00 μC/USB USB (Universal Serial Bus) is a communications bus allowing the transfer of information between one host and connected peripheral devices. The Nohau LPC2800 board includes a USB port which is connected to the LPC2888 USB module. This module supports the high-speed USB interface, whereby data transfer speeds of 480 Mb/s may be attained, but is backward compatible with the full-speed and low-speed modes. To take advantage of this hardware, μC/USB-Bulk, a USB bulk protocol stack, has been ported to this board. μC/USB-Bulk utilizes bulk transfers, one of the three data transfer methods between a host and its peripheral (the other two are isochronous and interrupt transfers). The simplicity and speed of the bulk transfer protocol enables the stack to be easily ported, while providing a logical transfer method for bursty or intermittent communications, as might be expected on a mass storage device. μC/USB-Bulk is independent of both hardware and the operating system, so two ports, one for each of the hardware and OS, must be provided. The LPC2888-specific driver implemented (as all hardware drivers must) the following functions: 4.01 Initialization function: • USB_HW_Init() Buffer control functions: • USB_HW_BufferAvailable() • USB_HW_FreeBuffer() Input/output functions: • USB_HW_Read() • USB_HW_SendData() Controller setup functions: • USB_HW_Attach() • USB_HW_UnloadEP0() • USB_HW_StallEP0() • USB_HW_SetAddress() • USB_HW_EnableEp1() • USB_HW_EP0_Send() • USB_HW_ClearOutPacketReady() • USB_HW_ClrSetupEnd() Interrupt functions: • USB_HW_DisableRxInterrupt() • USB_HW_EnableRxInterrupt() Other functions: • USB_HW_memcpy() • USB_HW_ForceConfiguredState() LPC2888 USB Considerations The most current NXP user manual for the LPC2888, Rev. 01 dating from September 5, 2006, provides helpful information regarding the USB registers and covers the basic elements of the general USB controller. The more fundamental function considerations regarding setup of the endpoints and receipt of packets is more thoroughly covered in the documentation of NXP’s 25 Micriµm µC/OS-II, µC/OS-View and µC/USB for the NXP LPC2888 CPU ISP1582/3 USB controller. The ISP1582/3 has essentially the same interface as the LPC2888 USB controller and, more importantly, the operation of the two devices may be judged (nearly) identical given that the guidelines of the ISP1582/3 provided the necessary details for writing a driver for the LPC2888. The following documents were consulted for the port: the ISP1582 “Product Data” guide (revision 04); the ISP1582 firmware programming guide, AN10046 (revision 03); and the ISP1582 FAQs, NA 10046 (revision 05). Where one of these documents provides justification for a particular coding decision, as covered in the code listings below, citations will be given. The LCP2888 includes 8 physical endpoints (EP0 through EP7) and 16 logical endpoints (IN and OUT endpoints for each of EP0 through EP7). The host perspective is always considered when terming an endpoint “IN” or “OUT”, implying that an IN endpoint sends data to the host and an OUT endpoint receives data from the host. Four logical endpoints are used, two for the control transfers (EP0 IN and EP0 OUT) and two for the bulk transfers (EP1 IN and EP2 OUT), but, from a programming viewpoint, five endpoints are effectively considered. These are the four logical endpoints plus an EP0 SETUP endpoint to which the EP0 setup packets are routed. Each of these five has its own FIFO (accessed by the USBData register) and setup and control registers (USBEType, USBECtrl, USBMaxSize, and USBDCnt). The particular set of endpoint registers (such as that corresponding to EP1 IN) is selected by writing to the USBEIX (USB Index) register prior to any attempted access. USB control transfers are used during device enumeration, the process by which the host learns the peripheral’s capabilities and sets up the peripheral prior to the transfer of actual data. Each transfer involves three phases: 1) Setup phase. In this phase, the host informs the peripheral as to the type of transfer to expect (i.e., whether data will be sent to the host or received from the host) and the data which will be transferred. 2) Data phase. Data may be transferred from the peripheral to the host or from the host to the peripheral. Control transfers which require no transfer of data lack this phase. 3) Status phase. transfer. In this phase, the peripheral indicates the result of the data phase Interrupts will be received for the EP0 SETUP endpoint only when when the peripheral receives the setup packet during the setup phase, and the EP0 SETUP endpoint registers and FIFO will be used only when reading this packet (see Listing 4-3). The EP0 IN endpoint registers and FIFO are used during the data phase of a control transfer when the peripheral will send packets to the host (a data IN stage; see Listing 4-4). Similarly, the EP0 OUT endpoint registers and FIFO are used during the data phase when the the host will send additional packets to the peripheral (a data OUT stage; this type of transfer is not used in this driver). Interrupts are received on the EP0 IN and EP0 OUT in response to ACKs (acknowledgements) from the host. An IN ACK interrupt is received after the completion of the data phase on a control transfer with a data IN stage; an OUT ACK interrupt initiates the reading of data from the EP0 OUT FIFO during the data OUT stage of a control transfer. 26 Micriµm µC/OS-II, µC/OS-View and µC/USB for the NXP LPC2888 CPU 4.02 LPC2888 μC/USB Driver Details The application must call the functions USB_Init() and USB_X_Init() before commencing USB transfer. USB_Init() calls two functions from the hardware driver, USB_HW_Init() and USB_Attach(). After the former, the USB controller should be prepared to receive a bus reset interrupt. The latter should enable a pull-up on the DP pin, be it through the setting of an I/O pin or some functionality internal to the controller, causing the host to detect the presence of the device. The programmatic flow following this call is interrupt-driven, proceeding through enumeration, until the device is brought into a configured state. Figure 4-1 presents a basic flowchart of the USB control flow; portions of this diagram will be enlarged upon in later sections. Note that while the two steps are initiated by the device (or its user), the last three are controlled by the host. Initialize USB controller USB_HW_Init() USB_X_Init() Attach to host USB_HW_Attach() Be enumerated by host (See Figure 4-2) Transfer data USB_Read() USB_Write() Figure 4-1. Basic steps of using a USB connection: Flow (left); Function calls (right) Listing 4-1, USB_HW_Init() void { USB_HW_Init (void) USBCLKEN = USBCLKEN_CLKEN; USBMODE USBMODE |= USBMODE_SOFTRESET; &= ~USBMODE_SOFTRESET; USBMODE |= USBMODE_CLKAON; (1) (2) USBDEVADR = 0x00000000; (3) USBINTCFG = 0x00000054; (4) USBINTCLR = USBINT_ALL; USBEINTCLR = USBEINT_ALL; USBINTE = USBINT_BRESET; 27 Micriµm µC/OS-II, µC/OS-View and µC/USB for the NXP LPC2888 CPU USB_IntInit(); (5) USBMODE (6) |= USBMODE_GIE; } L4-1(1) The USB controller clock is not enabled immediately after reset (contrary to what is written in the LPC2888 documentation). L4-1(2) A soft reset is performed. L4-1(3) The device address is set to the default value, zero. L4-1(4) The interrupts are configured preparatory for a bus reset. First, the policy for interrupt generation and the polarity and parity of the interrupt signal are set using the USBINTCFG register. Second, all interrupts are cleared by writing the USBINTCLR and USBEINTCLR registers. Third, the bus reset interrupts is enabled. L4-1(5) The USB_IntInit() function, defined in bsp.c, is called to initialize the USB vectors within the LPC2888 interrupt controller and assign USB_ISR_Handler() as the interrupt handler. L4-1(6) Interrupts within the USB controller are enabled. Once the LPC2888 USB controller has been initialized and the pull-up on the DP pin has been enabled (using the SoftConnect feature), the host procedes with enumeration. Figure 4-2 presents the flow through this phase. Listing 4-2 presents the code for USB_ISR_Handler(), which receives all USB interrupts and routes each interrupt to the proper handler. 28 Micriµm µC/OS-II, µC/OS-View and µC/USB for the NXP LPC2888 CPU Receive bus reset interrupt; configure controller to receive EP0 setup packets USB_ISR_Reset() Receive EP0 interrupt; read setup packet Data IN phase? USB_ISR_EP0_ Setup() NO YES Move to data phase Move to status phase Transfer data Receive IN ACK interrupt; move to status phase Receive EP0 OUT interrupt NO USB_HW_ClearOut PacketReady() USB_HW_UnloadEP0() USB_ISR_EP0_Send() Receive IN ACK interrupt USB_ISR_EP0_IN() USB_ISR_EP0_OUT() Configured? YES Setup bulk endpoints USB_HW_EP1_ Enable() Figure 4-1. Enumeration process: Flow (left); Function calls (right) 29 USB_ISR_EP0_IN() Micriµm µC/OS-II, µC/OS-View and µC/USB for the NXP LPC2888 CPU Listing 4-2, USB_ISR_Handler() void { USB_ISR_Handler (void) USB_U32 USB_U32 USB_U32 USB_U32 USB_U32 int_status; int_enable; inte_status; inte_enable; pkt_size; int_status int_enable inte_status inte_enable = = = = USBINTSTAT; USBINTE; USBEINTSTAT; USBEINTE; int_status &= int_enable; inte_status &= inte_enable; (1) if (int_status & USBINT_EP0STAT) { USB_ISR_EP0_Setup(); USBINTCLR = USBINT_EP0STAT; } if (int_status & USBINT_BRESET) { USB_ISR_Reset(); USBINTCLR = USBINT_BRESET; } if (int_status & USBINT_SUSP) { if (int_status & USBINT_RESUME) { USBINTCLR = USBINT_SUSP | USBINT_RESUME; } else { USB_ISR_Suspend(); USBINTCLR = USBINT_SUSP; } } else if (int_status & USBINT_RESUME) { USB_ISR_Resume(); USBINTCLR = USBINT_RESUME; } (2) if (inte_status & USBEINT_EP0_OUT) { USB_ISR_EP0_OUT(); USBEINTCLR = USBEINT_EP0_OUT; } if (inte_status & USBEINT_EP0_IN) { USB_ISR_EP0_IN(); USBEINTCLR = USBEINT_EP0_IN; } if (inte_status & USBEINT_EP1_IN) { USB__OnTx(); USBEINTCLR = USBEINT_EP1_IN; } if (inte_status & USBEINT_EP2_OUT) { USBEIX = USBEIX_EP2_OUT; pkt_size = (USB_U32)USBDCNT; USB__OnRx(pkt_size); USBEINTCLR = USBEINT_EP2_OUT; } (5) (3) (4) (6) (7) (8) } L4-2(1) The currently triggered interrupts are ANDed with the currently enabled interrupts to prevent any unenabled interrupts from being handled. The structure of the handler function allows all enabled, triggered interrupts to be handled (assuming code has been placed in the function for a particular interrupt). L4-2(2) The interrupt generated by the receipt of an EP0 setup packet is handled (by the call to USB_ISR_EP0_Setup()) and then cleared. See Listings 4-4 and 4-5. L4-2(3) The interrupt generated by a bus reset is handled (by the call to USB_ISR_Reset()) and then cleared. See Listing 4-3. 30 Micriµm µC/OS-II, µC/OS-View and µC/USB for the NXP LPC2888 CPU L4-2(4) Suspend and resume from suspend interrupts are handled in the body of this if structure and its connected else. As directed in the answer to question 2.4 in the ISP1582 FAQ document (AN 10046), when both a suspend and resume interrupt occur, neither is handled, but both are cleared. Otherwise, the received suspend or resume from suspend interrupt is handled and cleared. L4-2(5) The EP0 OUT endpoint interrupt is handled and cleared. This interrupt is only received following the movement to the status stage of a control transfer with a data IN stage; however, according to the ISP1582 firmware programming guide (AN 10039), no interrupt should be generated in this circumstance. L4-2(6) The EP0 IN endpoint interrupt is handled and cleared. This interrupt is received following the completion of the data stage of a control transfer with a data IN stage, or following the movement to the status stage of a control transfer with no data stage. According to the ISP1582 firmware programming guide (AN 10039), no interrupt should be received in the latter circumstance. L4-2(7) The interrupt generated when the host wants to receive data is handled and cleared. L4-2(8) The interrupt generated when the host wants to transmit data is handled (after the number of bytes to receive has been read from USBDCNT) and cleared. Listing 4-3, USB_ISR_Reset() static void USB_ISR_Reset (void) { USBDEVADR = USBDEVADR_DEVEN; USBINTCFG = 0x00000054; (1) (2) USBEIX USBETYPE = USBEIX_EP0; = USBETYPE_ENABLE | USBETYPE_CTRL; USBEIX USBETYPE = USBEIX_EP0_IN; = USBETYPE_ENABLE | USBETYPE_CTRL; USBEIX USBETYPE = USBEIX_EP0_OUT; = USBETYPE_ENABLE | USBETYPE_CTRL; USBINTE = USBINT_BRESET | USBINT_EP0STAT | USBINT_SUSP | USBINT_RESUME; = USBEINT_EP0_IN | USBEINT_EP0_OUT; USBEINTE (3) (4) } L4-3(1) The LPC2888’s USB controller is enabled at the default address (zero). L4-3(2) The policy for interrupt generation set. L4-3(3) The EP0 setup, EP0 IN, and EP0 OUT endpoints are enabled as control endpoints. The maximum packet size will be set for the bulk endpoints, but, according to question 2.5 in the ISP1582 FAQs (AN 10046), doing so for the control endpoints could result in errors. L4-3(4) The interrupts and endpoint interrupts necessary for proceeding through enumeration of the device are enabled. 31 Micriµm µC/OS-II, µC/OS-View and µC/USB for the NXP LPC2888 CPU Listing 4-4, USB_HW_EP0_Setup() static void USB_ISR_EP0_Setup (void) { USB_U32 rx_word; USB_SETUP_PACKET pkt; USB_U32 rx_size; USBEIX rx_size = USBEIX_EP0; = USBDCNT; if (rx_size >= 8) { rx_word pkt.bmRequestType pkt.bRequest pkt.wValueLow pkt.wValueHigh = = = = = USBDATA; (USB_U8)( rx_word & (USB_U8)((rx_word >> 8) & (USB_U8)((rx_word >> 16) & (USB_U8)((rx_word >> 24) & 0x000000FF); 0x000000FF); 0x000000FF); 0x000000FF); = = = = = USBDATA; (USB_U8)( rx_word & (USB_U8)((rx_word >> 8) & (USB_U8)((rx_word >> 16) & (USB_U8)((rx_word >> 24) & 0x000000FF); 0x000000FF); 0x000000FF); 0x000000FF); rx_word pkt.wIndexLow pkt.wIndexHigh pkt.wLengthLow pkt.wLengthHigh (1) (2) USB__HandleSetup(&pkt); (3) } } L4-4(1) The EP0 setup endpoint is selected. L4-4(2) Though the verification is unnecessary, the packet size, which should be eight bytes, is checked. The eight bytes are retrieved from the FIFO via the EP0 setup endpoint’s USBDATA registered and stored in the packet passed to the function. L4-4(3) The µC/USB-Bulk function USB__HandleSetup() is called to determine the nature of the setup packet and request the appropriate action. There are three possible situations: 1) 2) 3) The request involves a data IN stage. In this case, USB_HW_ClearOutPacketReady() will be called to move the transfer to the data stage, and USB_HW_EP0_Send() will be called to transfer the data (see Listing 4-5). The request involves no data stage. In this case, USB_HW_Unload_EP0() is called to moving the transfer directly to the status stage (see Listing 4-5(4)). The request is either unknown or unhandled. EP0 is stalled in this situation. A fourth possibility, a control request with a data OUT stage, is not encountered during enumeration and, consequently, will not be handled by this document. 32 Micriµm µC/OS-II, µC/OS-View and µC/USB for the NXP LPC2888 CPU Listing 4-5, USB_HW_EP0_Send() void USB_HW_EP0_Send (const unsigned char *p_data, unsigned char nbytes, char tx_null_pkt) { USB_U32 USB_U8 tx_word; *p; USBEIX = USBEIX_EP0_IN; USBDCNT = nbytes; (1) p = (USB_U8 *)p_data; if (nbytes != 0) { if (nbytes >= 4) do { tx_word tx_word tx_word tx_word USBDATA { (2) = |= |= |= *(p *(p *(p *(p + + + + 0); 1) << 8; 2) << 16; 3) << 24; = tx_word; p += 4; nbytes -= 4; } while (nbytes >= 4); } if (nbytes--) { tx_word = *p++; if (nbytes--) { tx_word |= *p++ << 8; if (nbytes--) { tx_word |= *p++ << 16; } } USBDATA = tx_word; } } else { USBDCNT = 0; USBECTRL = USBECTRL_STATUS; } (3) (4) } L4-5(1) The EP0 IN endpoint is selected, and the number of bytes to send is written to its USBDCNT register. L4-5(2) The full four-byte words are written to the EP0 IN endpoint’s USBDATA register, one by one. L4-5(3) If the total number of bytes to send was not a multiple of four, the final word of data is assembled and written to the USBDCNT register. L4-5(4) If no bytes were to be sent, then the control transfer is moved to the status phase. In this case, USB_HW_EP0_Send() will have proceeded identically to USB_HW_Unload_EP0(), which moves a control transfer with no data phase to the status phase. 33 Micriµm µC/OS-II, µC/OS-View and µC/USB for the NXP LPC2888 CPU Listing 4-6, USB_HW_EnableEP1() void { USB_HW_EnableEP1 (void) USBEIX USBETYPE USBEIX USBETYPE USBEIX USBETYPE USBEIX USBETYPE = = = = = = = = USBEIX_EP1_IN; 0x00000000; USBEIX_EP1_OUT; 0x00000000; USBEIX_EP2_IN; 0x00000000; USBEIX_EP2_OUT; 0x00000000; (1) USBEIX USBMAXSIZE USBEIX USBMAXSIZE USBEIX USBMAXSIZE USBEIX USBMAXSIZE = = = = = = = = USBEIX_EP1_IN; 0x00000040; USBEIX_EP1_OUT; 0x00000040; USBEIX_EP2_IN; 0x00000040; USBEIX_EP2_OUT; 0x00000040; (2) USBEIX USBETYPE = = | = = | = = | = = | USBEIX_EP1_IN; USBETYPE_BULK USBETYPE_ENABLE; USBEIX_EP1_OUT; USBETYPE_BULK USBETYPE_ENABLE; USBEIX_EP2_IN; USBETYPE_BULK USBETYPE_ENABLE; USBEIX_EP2_OUT; USBETYPE_BULK USBETYPE_ENABLE; (3) |= USBEINT_EP1_IN | USBEINT_EP2_OUT; (4) USBEIX USBETYPE USBEIX USBETYPE USBEIX USBETYPE USBEINTE } L4-6(1) The answer to ISP1582 FAQ 2.15 (AN 100046) provides clear directions for the initialization of endpoints, which, when done improperly, may cause data corruption. In the first step, all endpoints which will be used should be disabled. (The ISP1582 firmware programming guide provides one additional instruction: both the IN and the OUT endpoint should be initialized for any logical endpoint number for which either the IN or OUT endpoint is used. Consequently, the EP2 IN and EP1 OUT endpoints, which are unused in this driver, are initialized by this function.) L4-6(2) The maximum packet size is set to 64 for each endpoint. L4-6(3) The endpoint type for each endpoint is selected, and the endpoints are enabled. L4-6(4) The interrupts for the endpoints which will be used are enabled. 34 Micriµm µC/OS-II, µC/OS-View and µC/USB for the NXP LPC2888 CPU 4.03 μC/USB-Bulk Example Enumeration The sequence of interrupts during enumeration depends on the host and the device driver. Figure 4-3 presents an example enumeration sequence which culminated in successful reads and writes to the LPC2888 from a personal computer running Windows XP. As mentioned in the previous sections, interrupts are received unexpectedly in two situations: 1) An EP0 IN interrupt is received following the movement to the status phase of a control transfer with no data phase. 2) An EP0 OUT interrupt is received following the movement to the status phase of a control transfer with a data IN phase. Int. # 0 1 2 3 4 5 6 7 8 9 10 11* 14* 17* 20* 23* 26* 29* 32* 35* 38* 41 42 43 44 45 Setup Packet Meaning Request Request Value Index Length Type 0 0 0 0 0 Bus reset 0 0x80 0x06 0x0100 0x0000 0x0040 Get device descr. EP0 setup 0 0 0 0 0 EP0 IN 0 0 0 0 0 0 EP0 OUT 0 0 0 0 0 0 Susp./Res. 0 0 0 0 0 0 Bus reset 0 0x00 0x05 0x0003 0x0000 0x0000 Set address EP0 setup 0 0 0 0 0 EP0 IN 0 0x80 0x06 0x0100 0x0000 0x0012 Get device descr EP0 setup 0 0 0 0 0 EP0 IN 0 0 0 0 0 0 EP0 OUT 0 0x80 0x06 0x0200 0x0000 0x0009 Get config. descr EP0 setup 0x80 0x06 0x0300 0x0000 0x00FF Get language ID EP0 setup 0x80 0x06 0x0303 0x0409 0x00FF Get serial num. EP0 setup 0x80 0x06 0x0200 0x0000 0x00FF Get config. descr EP0 setup 0x80 0x06 0x0300 0x0000 0x00FF Get language ID EP0 setup 0x80 0x06 0x0302 0x0409 0x00FF Get product ID EP0 setup 0x80 0x06 0x0300 0x0000 0x00FF Get language ID EP0 setup 0x80 0x06 0x0302 0x0409 0x00FF Get product ID EP0 setup 0x80 0x06 0x0100 0x0000 0x0012 Get device descr EP0 setup 0x80 0x06 0x0200 0x0000 0x0009 Get config. descr EP0 setup 0x80 0x06 0x0200 0x0000 0x0020 Get config. descr EP0 setup 0 0 0 0 0 EP0 IN 0 0 0 0 0 0 EP0 OUT 0 0x00 0x09 0x0001 0x0000 0x0000 Set configuration EP0 setup 0 0 0 0 0 EP0 IN 0 Interrupt Figure 4-3. Example enumeration sequence. * Each of these interrupts, like interrupts numbers 8 and 40, is followed by an EP0 IN and an EP0 OUT interrupt. 35 Micriµm µC/OS-II, µC/OS-View and µC/USB for the NXP LPC2888 CPU 4.04 μC/USB-Bulk Example µC/USB-Bulk includes a sample application which performs a simple test of the bulk communication on the device. This application, which is located in \Micrium\Software\uC-USB-Bulk\SampleApp continuously alternates between writes to and reads from the device. The application expects that the value it reads will be one greater than the value it previously wrote. Once Windows has enumerated the device, run the application (by clicking on the executable, for instance). If the device is properly connected (and continues to be connected), no message boxes should appear; the output in the terminal window should merely indicate the input and output transfers as such occur (as shown in Figure 4-4). However, if the application fails to connect to the device or if the data read is otherwise than the expected value, a message box (like in Figure 4-5) should appear with a warning. When this message box is closed, the application will exit. Figure 4-4. Example Output from SampleApp Figure 4-5. Message Box Indicating Error in SampleApp 36 Micriµm µC/OS-II, µC/OS-View and µC/USB for the NXP LPC2888 CPU 5.00 µC/OS-View The application code described in this application note allows you to connect a Windows-based PC to your target and display run-time information about your target in a Window as shown in Figure 5-1. This is done via an add-on module called µC/OS-View. Figure 5-1, µC/OS-View Windows’ ‘Viewer’ Note that you can ‘disable’ µC/OS-View by removing the µC/OS-View files from the build and setting OS_VIEW_MODULE to 0 in os_cfg.h. You would need to do this is you didn’t purchase µC/OS-View from Micriµm. µC/OS-View is a combination of a Microsoft Windows application program and code that resides in your target system (in this case, the LPC2888 Evaluation Board). The Windows application connects to your system via an RS-232C serial port. The status of the tasks which are managed by µC/OS-II can be viewed with the Windows application. µC/OS-View allows you to view the following information from a µC/OS-II based product: • The address of the TCB of each task (up to 63 tasks); • The name of each task (up to 63 tasks); • The status (e.g., ready, delayed, waiting on event) of each task; • The number of ticks remaining for a timeout or if a task is delayed; 37 Micriµm µC/OS-II, µC/OS-View and µC/USB for the NXP LPC2888 CPU • The amount of stack space used and left for each task; • The percentage of CPU time each task relative to all the tasks; • The number of times each task has been 'switched-in'; and • The execution profile of each task. µC/OS-View also allows you to send commands to your target and allow your target to reply back and display information in a 'terminal window'. µC/OS-View is licensed on a per-developer basis. In other words, you are allowed to install µC/OS-View on multiple PCs as long as the PC is used by the same developer. If multiple developers are using µC/OS-View then each needs to obtain his own copy. Contact Micriµm for pricing information. 38 Micriµm µC/OS-II, µC/OS-View and µC/USB for the NXP LPC2888 CPU Licensing μC/OS-II is provided in source form for FREE evaluation, for educational use or for peaceful research. If you plan on using μC/OS-II in a commercial product you need to contact Micriμm to properly license its use in your product. We provide ALL the source code with this application note for your convenience and to help you experience μC/OS-II. The fact that the source is provided does NOT mean that you can use it without paying a licensing fee. Please help us continue to provide the Embedded community with the finest software available. Your honesty is greatly appreciated. References µC/OS-II, The Real-Time Kernel, 2nd Edition Jean J. Labrosse R&D Technical Books, 2002 ISBN 1-57820-103-9 Embedded Systems Building Blocks Jean J. Labrosse R&D Technical Books, 2000 ISBN 0-87930-604-1 Contacts IAR Systems Century Plaza 1065 E. Hillsdale Blvd Foster City, CA 94404 USA +1 650 287 4250 +1 650 287 4253 (FAX) e-mail: [email protected] WEB : www.IAR.com CMP Books, Inc. 1601 W. 23rd St., Suite 200 Lawrence, KS 66046-9950 USA +1 785 841 1631 +1 785 841 2624 (FAX) e-mail: [email protected] WEB: http://www.cmpbooks.com Micriµm 949 Crestview Circle Weston, FL 33327 USA +1 954 217 2036 +1 954 217 2037 (FAX) e-mail: [email protected] WEB: www.Micrium.com NXP 1110 Ringwood Court San Jose, CA 95131 USA +1 408 474 8142 WEB: www.nxp.com 39