o add usb test

This commit is contained in:
david 2009-02-17 09:36:51 +01:00
parent 4fad7cab6d
commit 920913d9e1
27 changed files with 3285 additions and 16 deletions

View File

@ -15,7 +15,7 @@
*/
/*#define HW_ENDPOINT_LINUX*/
/*#define HW_ENDPOINT_ATMEGA128_SD*/
/*#define HW_ENDPOINT_ATMEGA128_SD*/
#define HW_ENDPOINT_LPC2000_SD

View File

@ -166,7 +166,7 @@ struct FileRecord{
euint32 FileSize;
};
#else
#warning "mt ATTR_PACKED active"
//#warning "mt ATTR_PACKED active"
struct FileRecord{
euint8 FileName[11];
euint8 Attribute;

View File

@ -18,6 +18,8 @@
#include "efs.h"
#include "ls.h"
#include "mkfs.h"
#include "types.h"
#include "debug.h"
#include "interfaces/efsl_dbg_printf_arm.h"
#define rprintf efsl_debug_printf_arm
@ -31,7 +33,7 @@
#define LEDDIR IODIR0
#define LEDSET IOSET0
#define LEDCLR IOCLR0
static char LogFileName[] = "dummy.log";
static char rom_filename[] = "SPRITE.SMC";
static void gpioInit(void)
{
@ -53,6 +55,17 @@ DirList list;
unsigned short e;
unsigned char buf[513];
void cleanup_name(filename,sfn){
while(*filename != '\0'){
if(*filename=='.' && !dot){
dot=1;
c=8;
}else{
}
void list_roms(){
uint8_t cnt = 0;
rprintf("Directory of 'root':\n");
@ -78,13 +91,41 @@ uint8_t * get_filename(uint8_t idx){
return NULL;
}
void dump_packet(uint32_t addr,uint32_t len,uint8_t *packet){
uint16_t i,j;
uint16_t sum =0;
for (i=0;i<len;i+=16) {
sum = 0;
for (j=0;j<16;j++) {
sum +=packet[i+j];
}
if (!sum)
continue;
DBG((TXT("%08x:"), addr + i));
for (j=0;j<16;j++) {
DBG((TXT(" %02x"), packet[i+j]));
}
DBG((TXT(" |")));
for (j=0;j<16;j++) {
if (packet[i+j]>=33 && packet[i+j]<=126 )
DBG((TXT("%c"), packet[i+j]));
else
DBG((TXT(".")));
}
DBG((TXT("|\n")));
}
}
void dump_filename(uint8_t * filename){
uint32_t cnt = 0;
if (file_fopen(&filer, &efs.myFs, filename, 'r') == 0) {
rprintf("File %s open. Content:\n", filename);
while ((e = file_read(&filer, 512, buf)) != 0) {
buf[e] = '\0';
uart0Puts((char *) buf);
dump_packet(cnt,e,buf);
cnt+=e;
}
DBG((TXT("Len %08x(%li)\n"), cnt,cnt));
rprintf("\n");
file_fclose(&filer);
} else {
@ -100,6 +141,7 @@ int main(void)
int ch;
int8_t res;
uint8_t * filename;
uint8_t fatfilename[12];
Initialize();
gpioInit();
@ -120,21 +162,21 @@ int main(void)
uart0Puts("You pressed : ");
uart0Putch(ch);
uart0Puts("\r\n");
if (ch == 'r') {
if (file_fopen(&filer, &efs.myFs, LogFileName, 'r') == 0) {
rprintf("File %s open. Content:\n", LogFileName);
while ((e = file_read(&filer, 512, buf)) != 0) {
buf[e] = '\0';
uart0Puts((char *) buf);
} rprintf("\n");
file_fclose(&filer);
}
}
if (ch >='1' && ch <='9'){
filename = get_filename(ch - 48);
rprintf("Dump: %s\n",filename);
file_normalToFatName(filename,fatfilename);
rprintf("Filename: '%s'\n",filename);
dump_filename(filename);
rprintf("Fatfilename: '%s'\n",fatfilename);
dump_filename(fatfilename);
file_normalToFatName("sprite.smc",fatfilename);
rprintf("Fatfilename: '%s'\n",fatfilename);
dump_filename(fatfilename);
file_normalToFatName("sprite .smc",fatfilename);
rprintf("Fatfilename: '%s'\n",fatfilename);
dump_filename(fatfilename);
//dump_filename(rom_filename);
}
ledToggle();

View File

@ -0,0 +1,19 @@
# app defs
EXE = custom_client
ifndef LIBUSB
LIBUSB = "/opt/local/"
endif
# tool defs
CFLAGS = -W -Wall -g -I$(LIBUSB)/include
LIBS = -L$(LIBUSB)/lib -lusb
all: $(EXE)
$(EXE): main.o
$(CC) -o $(EXE) $< $(LIBS)
clean:
$(RM) $(EXE) main.o

View File

@ -0,0 +1,193 @@
/*
LPCUSB, an USB device driver for LPC microcontrollers
Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
Simple benchmarking application.
It talks with the 'custom' device application on the LPC214x through
libusb.
*/
#include <stdio.h>
#include <unistd.h>
#include <sys/timeb.h>
#include "usb.h"
// types
#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
#endif
typedef unsigned int U32;
typedef unsigned char U8;
#define MAX_TIME 3000
static unsigned char abData[16384];
// USB device specific definitions
#define VENDOR_ID 0xFFFF
#define PRODUCT_ID 0x0004
#define BM_REQUEST_TYPE (2<<5)
#define BULK_IN_EP 0x82
#define BULK_OUT_EP 0x05
// this structure should match with the expectations of the 'custom' device!
typedef struct {
U32 dwAddress;
U32 dwLength;
} TMemoryCmd;
static struct usb_device * find_device(int iVendor, int iProduct)
{
struct usb_bus *usb_bus;
struct usb_device *dev;
for (usb_bus = usb_get_busses(); usb_bus; usb_bus = usb_bus->next) {
for (dev = usb_bus->devices; dev; dev = dev->next) {
if ((dev->descriptor.idVendor == iVendor) &&
(dev->descriptor.idProduct == iProduct)) {
return dev;
}
}
}
return NULL;
}
static struct timeb start;
static void starttimer(void)
{
ftime(&start);
}
static int stoptimer(void)
{
struct timeb now;
ftime(&now);
return 1000 * (now.time - start.time) + now.millitm - start.millitm;
}
int main(int argc, char *argv[])
{
struct usb_device *dev;
struct usb_dev_handle *hdl;
int i, j;
U32 dwBlockSize, dwChunk, dwBytes;
TMemoryCmd MemCmd;
int iTimer;
usb_init();
usb_find_busses();
usb_find_devices();
dev = find_device(VENDOR_ID, PRODUCT_ID);
if (dev == NULL) {
fprintf(stderr, "device not found\n");
return -1;
}
hdl = usb_open(dev);
i = usb_set_configuration(hdl, 1);
if (i < 0) {
fprintf(stderr, "usb_set_configuration failed\n");
}
i = usb_claim_interface(hdl, 0);
if (i < 0) {
fprintf(stderr, "usb_claim_interface failed %d\n", i);
return -1;
}
// read some data
for (j = 6; j < 15; j++) {
dwBlockSize = (1 << j);
fprintf(stderr, "Testing blocksize %5d\n", dwBlockSize);
fprintf(stderr, "* read :");
// send a vendor request for a read
MemCmd.dwAddress = 0;
MemCmd.dwLength = 1024 * 1024;
i = usb_control_msg(hdl, BM_REQUEST_TYPE, 0x01, 0, 0, (char *)&MemCmd, sizeof(MemCmd), 1000);
if (i < 0) {
fprintf(stderr, "usb_control_msg failed %d\n", i);
}
dwBytes = 0;
starttimer();
while (MemCmd.dwLength > 0) {
dwChunk = MIN(dwBlockSize, MemCmd.dwLength);
i = usb_bulk_read(hdl, 0x82, (char *)abData, dwBlockSize, 2000);
if (i < 0) {
fprintf(stderr, "usb_bulk_read failed %d\n", i);
break;
}
MemCmd.dwLength -= dwChunk;
dwBytes += dwBlockSize;
if (stoptimer() > MAX_TIME) {
break;
}
}
iTimer = stoptimer();
fprintf(stderr, " %7d bytes in %d ms = %d kB/s\n", dwBytes, iTimer, dwBytes / iTimer);
// stdout
printf("%d,%d,%d,", dwBlockSize, dwBytes, iTimer);
fprintf(stderr, "* write:");
// send a vendor request for a write
MemCmd.dwAddress = 0;
MemCmd.dwLength = 1024 * 1024;
i = usb_control_msg(hdl, BM_REQUEST_TYPE, 0x02, 0, 0, (char *)&MemCmd, sizeof(MemCmd), 1000);
if (i < 0) {
fprintf(stderr, "usb_control_msg failed %d\n", i);
}
dwBytes = 0;
starttimer();
while (MemCmd.dwLength > 0) {
dwChunk = MIN(dwBlockSize, MemCmd.dwLength);
i = usb_bulk_write(hdl, 0x05, (char *)abData, dwBlockSize, 2000);
if (i < 0) {
fprintf(stderr, "usb_bulk_read failed %d\n", i);
break;
}
MemCmd.dwLength -= dwChunk;
dwBytes += dwBlockSize;
if (stoptimer() > MAX_TIME) {
break;
}
}
fprintf(stderr, " %7d bytes in %d ms = %d kB/s\n", dwBytes, iTimer, dwBytes / iTimer);
// stdout
printf("%d,%d,%d\n", dwBlockSize, dwBytes, iTimer);
}
usb_release_interface(hdl, 0);
usb_close(hdl);
return 0;
}

View File

@ -0,0 +1,52 @@
LIBNAME = usbstack
# Package definitions
PKG_NAME = target
DATE = $$(date +%Y%m%d)
# Tool definitions
CC = arm-elf-gcc
LD = arm-elf-ld -v
AR = arm-elf-ar
AS = arm-elf-as
CP = arm-elf-objcopy
OD = arm-elf-objdump
RM = rm
TAR = tar
CFLAGS = -I./ -I../ -c -W -Wall -Os -g -DDEBUG -mcpu=arm7tdmi
ARFLAGS = -rcs
LIBSRCS = usbhw_lpc.c usbcontrol.c usbstdreq.c usbinit.c
LIBOBJS = $(LIBSRCS:.c=.o)
all: depend lib examples
clean:
$(RM) -f $(LIBNAME).a $(LIBOBJS) .depend
make -C custom clean
custom:
make -C custom
# build lib
lib: $(LIBNAME).a
$(LIBNAME).a: $(LIBOBJS)
$(AR) $(ARFLAGS) $@ $^
# Builds release tar file
dist: clean
cd .. && $(TAR) --exclude={CVS,cvs} -cvzf $(PKG_NAME)-$(DATE).tar.gz $(PKG_NAME)
# recompile if the Makefile changes
$(LIBOBJS): Makefile
# dependency checking
depend: $(LIBSRCS)
$(CC) $(CFLAGS) -MM $^ > .depend || rm -f .depend
# phony targets
.PHONY: all clean examples depend
-include .depend

View File

@ -0,0 +1,55 @@
LIBNAME = ../usbstack
APPNAME = main
# Tool definitions
CC = arm-elf-gcc
LD = arm-elf-ld -v
AR = arm-elf-ar
AS = arm-elf-as
CP = arm-elf-objcopy
OD = arm-elf-objdump
RM = rm
# Tool flags
CFLAGS = -I./ -I../ -c -W -Wall -Os -g -DDEBUG -mcpu=arm7tdmi
ASFLAGS = -ahls -mapcs-32 -o crt.o
LFLAGS = -nostartfiles --warn-common
CPFLAGS = -O ihex
ODFLAGS = -x --syms
LINKFILE = lpc2148-rom.ld
CSRCS = startup.c printf.c console.c
OBJS = crt.o $(CSRCS:.c=.o)
EXAMPLES = custom
all: depend $(EXAMPLES)
custom: $(OBJS) main_custom.o $(LIBNAME).a
$(EXAMPLES):
@ echo "Building $@ example..."
$(CC) -T $(LINKFILE) $(LFLAGS) $^ -o $@.elf -Wl,-Map,$@.map
$(CP) $(CPFLAGS) $@.elf $@.hex
$(CP) -O binary $@.elf $@.bin
$(OD) $(ODFLAGS) $@.elf > $@.dmp
crt.o: crt.s
@ echo ".assembling"
$(CC) -c $(AFLAGS) -Wa,-ahlms=crt.lst crt.s -o crt.o
clean:
rm -f *.hex *.elf *.o *.lst *.dmp *.map .depend
# recompile if the Makefile changes
$(OBJS): Makefile
# dependency checking
depend: $(CSRCS)
$(CC) $(CFLAGS) -MM $^ > .depend || rm -f .depend
# phony targets
.PHONY: clean
-include .depend

View File

@ -0,0 +1,65 @@
/*
Simple console input/output, over serial port #0
Partially copied from Jim Lynch's tutorial
*/
#include "console.h"
#define PINSEL0 *(volatile unsigned int *)0xE002C000
#define U0THR *(volatile unsigned int *)0xE000C000
#define U0RBR *(volatile unsigned int *)0xE000C000
#define U0DLL *(volatile unsigned int *)0xE000C000
#define U0DLM *(volatile unsigned int *)0xE000C004
#define U0FCR *(volatile unsigned int *)0xE000C008
#define U0LCR *(volatile unsigned int *)0xE000C00C
#define U0LSR *(volatile unsigned int *)0xE000C014
/* Initialize Serial Interface */
void ConsoleInit(int iDivider)
{
PINSEL0 = (PINSEL0 & ~0x0000000F) | 0x00000005; /* Enable RxD0 and TxD0 */
U0LCR = 0x83; /* 8 bits, no Parity, 1 Stop bit */
U0DLL = iDivider & 0xFF; /* set divider / baud rate */
U0DLM = iDivider >> 8;
U0LCR = 0x03; /* DLAB = 0 */
// enable FIFO
U0FCR = 1;
}
/* Write character to Serial Port */
int putchar(int ch)
{
if (ch == '\n') {
while (!(U0LSR & 0x20));
U0THR = '\r';
}
while (!(U0LSR & 0x20));
U0THR = ch;
return ch;
}
int getchar (void) { /* Read character from Serial Port */
while (!(U0LSR & 0x01));
return (U0RBR);
}
int puts(char *s)
{
while (*s) {
putchar(*s++);
}
putchar('\n');
return 1;
}

View File

@ -0,0 +1,5 @@
void ConsoleInit(int iDivider);
int putchar(int c);
int puts(char *s);

View File

@ -0,0 +1,110 @@
/* ***************************************************************************************************************
crt.s STARTUP ASSEMBLY CODE
-----------------------
Module includes the interrupt vectors and start-up code.
*************************************************************************************************************** */
/* Stack Sizes */
.set UND_STACK_SIZE, 0x00000040 /* stack for "undefined instruction" interrupts is 4 bytes */
.set ABT_STACK_SIZE, 0x00000040 /* stack for "abort" interrupts is 4 bytes */
.set FIQ_STACK_SIZE, 0x00000040 /* stack for "FIQ" interrupts is 4 bytes */
.set IRQ_STACK_SIZE, 0X00000040 /* stack for "IRQ" normal interrupts is 4 bytes */
.set SVC_STACK_SIZE, 0x00000400 /* stack for "SVC" supervisor mode is 4 bytes */
/* Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs (program status registers) */
.set MODE_USR, 0x10 /* Normal User Mode */
.set MODE_FIQ, 0x11 /* FIQ Processing Fast Interrupts Mode */
.set MODE_IRQ, 0x12 /* IRQ Processing Standard Interrupts Mode */
.set MODE_SVC, 0x13 /* Supervisor Processing Software Interrupts Mode */
.set MODE_ABT, 0x17 /* Abort Processing memory Faults Mode */
.set MODE_UND, 0x1B /* Undefined Processing Undefined Instructions Mode */
.set MODE_SYS, 0x1F /* System Running Priviledged Operating System Tasks Mode */
.set I_BIT, 0x80 /* when I bit is set, IRQ is disabled (program status registers) */
.set F_BIT, 0x40 /* when F bit is set, FIQ is disabled (program status registers) */
.text
.arm
.global Reset_Handler
.global _startup
.func _startup
_startup:
# Exception Vectors
_vectors: ldr PC, Reset_Addr
ldr PC, Undef_Addr
ldr PC, SWI_Addr
ldr PC, PAbt_Addr
ldr PC, DAbt_Addr
nop /* Reserved Vector (holds Philips ISP checksum) */
ldr PC, [PC,#-0xFF0] /* see page 71 of "Insiders Guide to the Philips ARM7-Based Microcontrollers" by Trevor Martin */
ldr PC, FIQ_Addr
Reset_Addr: .word Reset_Handler /* defined in this module below */
Undef_Addr: .word UNDEF_Routine /* defined in main.c */
SWI_Addr: .word SWI_Routine /* defined in main.c */
PAbt_Addr: .word UNDEF_Routine /* defined in main.c */
DAbt_Addr: .word UNDEF_Routine /* defined in main.c */
IRQ_Addr: .word IRQ_Routine /* defined in main.c */
FIQ_Addr: .word FIQ_Routine /* defined in main.c */
.word 0 /* rounds the vectors and ISR addresses to 64 bytes total */
# Reset Handler
Reset_Handler:
/* Setup a stack for each mode - note that this only sets up a usable stack
for User mode. Also each mode is setup with interrupts initially disabled. */
ldr r0, =_stack_end
msr CPSR_c, #MODE_UND|I_BIT|F_BIT /* Undefined Instruction Mode */
mov sp, r0
sub r0, r0, #UND_STACK_SIZE
msr CPSR_c, #MODE_ABT|I_BIT|F_BIT /* Abort Mode */
mov sp, r0
sub r0, r0, #ABT_STACK_SIZE
msr CPSR_c, #MODE_FIQ|I_BIT|F_BIT /* FIQ Mode */
mov sp, r0
sub r0, r0, #FIQ_STACK_SIZE
msr CPSR_c, #MODE_IRQ|I_BIT|F_BIT /* IRQ Mode */
mov sp, r0
sub r0, r0, #IRQ_STACK_SIZE
msr CPSR_c, #MODE_SVC|I_BIT|F_BIT /* Supervisor Mode */
mov sp, r0
sub r0, r0, #SVC_STACK_SIZE
msr CPSR_c, #MODE_SYS|I_BIT|F_BIT /* User Mode */
mov sp, r0
/* copy .data section (Copy from ROM to RAM) */
ldr R1, =_etext
ldr R2, =_data
ldr R3, =_edata
1: cmp R2, R3
ldrlo R0, [R1], #4
strlo R0, [R2], #4
blo 1b
/* Clear .bss section (Zero init) */
mov R0, #0
ldr R1, =_bss_start
ldr R2, =_bss_end
2: cmp R1, R2
strlo R0, [R1], #4
blo 2b
/* Enter the C code */
b main
.endfunc
.end

View File

@ -0,0 +1,7 @@
halt
wait_halt
sleep 10
poll
flash erase_sector 0 0 14
flash write_bank 0 /Users/david/Devel/arch/arm/code/lpcusb/examples/custom.bin 0
reset run

View File

@ -0,0 +1,197 @@
/* ****************************************************************************************************** */
/* demo2148_blink_flash.cmd LINKER SCRIPT */
/* */
/* */
/* The Linker Script defines how the code and data emitted by the GNU C compiler and assembler are */
/* to be loaded into memory (code goes into FLASH, variables go into RAM). */
/* */
/* Any symbols defined in the Linker Script are automatically global and available to the rest of the */
/* program. */
/* */
/* To force the linker to use this LINKER SCRIPT, just add the -T demo2148_blink_flash.cmd directive */
/* to the linker flags in the makefile. */
/* */
/* LFLAGS = -Map main.map -nostartfiles -T demo2148_blink_flash.cmd */
/* */
/* */
/* The Philips boot loader supports the ISP (In System Programming) via the serial port and the IAP */
/* (In Application Programming) for flash programming from within your application. */
/* */
/* The boot loader uses RAM memory and we MUST NOT load variables or code in these areas. */
/* */
/* RAM used by boot loader: 0x40000120 - 0x400001FF (223 bytes) for ISP variables */
/* 0x40007FE0 - 0x4000FFFF (32 bytes) for ISP and IAP variables */
/* 0x40007EE0 - 0x40007FE0 (256 bytes) stack for ISP and IAP */
/* */
/* */
/* MEMORY MAP */
/* | |0x40008000 */
/* .-------->|---------------------------------| */
/* . | variables and stack |0x40007FFF */
/* ram_isp_high | for Philips boot loader | */
/* . | 32 + 256 = 288 bytes | */
/* . | | */
/* . | Do not put anything here |0x40007EE0 */
/* .-------->|---------------------------------| */
/* | UDF Stack 4 bytes |0x40007EDC <---------- _stack_end */
/* .-------->|---------------------------------| */
/* | ABT Stack 4 bytes |0x40007ED8 */
/* .-------->|---------------------------------| */
/* | FIQ Stack 4 bytes |0x40007ED4 */
/* .-------->|---------------------------------| */
/* | IRQ Stack 4 bytes |0x40007ED0 */
/* .-------->|---------------------------------| */
/* | SVC Stack 4 bytes |0x40007ECC */
/* .-------->|---------------------------------| */
/* . | |0x40007EC8 */
/* . | stack area for user program | */
/* . | | | */
/* . | | | */
/* . | | | */
/* . | V | */
/* . | | */
/* . | | */
/* . | | */
/* . | free ram | */
/* ram | | */
/* . | | */
/* . | | */
/* . |.................................|0x40000234 <---------- _bss_end */
/* . | | */
/* . | .bss uninitialized variables | */
/* . |.................................|0x40000218 <---------- _bss_start, _edata */
/* . | | */
/* . | .data initialized variables | */
/* . | |0x40000200 <---------- _data */
/* .-------->|---------------------------------| */
/* . | variables used by |0x400001FF */
/* ram_isp_low | Philips boot loader | */
/* . | 223 bytes |0x40000120 */
/* .-------->|---------------------------------| */
/* . | |0x4000011F */
/* ram_vectors | free ram | */
/* . |---------------------------------|0x40000040 */
/* . | |0x4000003F */
/* . | Interrupt Vectors (re-mapped) | */
/* . | 64 bytes |0x40000000 */
/* .-------->|---------------------------------| */
/* | | */
/* */
/* */
/* */
/* | | */
/* .--------> |---------------------------------| */
/* . | |0x0001FFFF */
/* . | | */
/* . | | */
/* . | | */
/* . | | */
/* . | | */
/* . | unused flash eprom | */
/* . | | */
/* . |.................................|0x0000032c */
/* . | | */
/* . | copy of .data area | */
/* flash | | */
/* . |---------------------------------|0x00000314 <----------- _etext */
/* . | | */
/* . | |0x00000180 main */
/* . | |0x00000278 feed */
/* . | main() |0x000002c4 FIQ_Routine */
/* . | |0x000002d8 SWI_Routine */
/* . | |0x000002ec UNDEF_Routine */
/* . | |0x000002b0 IRQ_routine */
/* . |---------------------------------|0x000001cc initialize */
/* . | |0x000000D4 */
/* . | Startup Code | */
/* . | (assembler) | */
/* . | | */
/* . |---------------------------------|0x00000040 Reset_Handler */
/* . | |0x0000003F */
/* . | Interrupt Vector Table (unused) | */
/* . | 64 bytes | */
/* .--------->|---------------------------------|0x00000000 _startup *
/* */
/* */
/* The easy way to prevent the linker from loading anything into a memory area is to define */
/* a MEMORY region for it and then avoid assigning any .text, .data or .bss sections into it. */
/* */
/* */
/* MEMORY */
/* { */
/* ram_isp_low(A) : ORIGIN = 0x40000120, LENGTH = 223 */
/* */
/* } */
/* */
/* */
/* Author: James P. Lynch */
/* */
/* ****************************************************************************************************** */
/* identify the Entry Point */
ENTRY(_startup)
/* specify the LPC2148 memory areas */
MEMORY
{
flash : ORIGIN = 0, LENGTH = 512K /* FLASH ROM */
ram_isp_low(A) : ORIGIN = 0x40000120, LENGTH = 223 /* variables used by Philips ISP bootloader */
ram : ORIGIN = 0x40000200, LENGTH = 32513 /* free RAM area */
ram_isp_high(A) : ORIGIN = 0x40007FE0, LENGTH = 32 /* variables used by Philips ISP bootloader */
ram_usb_dma : ORIGIN = 0x7FD00000, LENGTH = 8192 /* on-chip USB DMA RAM area (not used) */
}
/* define a global symbol _stack_end */
_stack_end = 0x40007EDC;
/* now define the output sections */
SECTIONS
{
. = 0; /* set location counter to address zero */
startup : { *(.startup)} >ram /* the startup code goes into FLASH */
.text : /* collect all sections that should go into FLASH after startup */
{
*(.text) /* all .text sections (code) */
*(.rodata) /* all .rodata sections (constants, strings, etc.) */
*(.rodata*) /* all .rodata* sections (constants, strings, etc.) */
*(.glue_7) /* all .glue_7 sections (no idea what these are) */
*(.glue_7t) /* all .glue_7t sections (no idea what these are) */
_etext = .; /* define a global symbol _etext just after the last code byte */
} >ram /* put all the above into FLASH */
.data : /* collect all initialized .data sections that go into RAM */
{
_data = .; /* create a global symbol marking the start of the .data section */
*(.data) /* all .data sections */
_edata = .; /* define a global symbol marking the end of the .data section */
} >ram AT >ram /* put all the above into RAM (but load the LMA copy into FLASH) */
.bss : /* collect all uninitialized .bss sections that go into RAM */
{
_bss_start = .; /* define a global symbol marking the start of the .bss section */
*(.bss) /* all .bss sections */
} >ram /* put all the above in RAM (it will be cleared in the startup code */
. = ALIGN(4); /* advance location counter to the next 32-bit boundary */
_bss_end = . ; /* define a global symbol marking the end of the .bss section */
}
_end = .; /* define a global symbol marking the end of application RAM */

View File

@ -0,0 +1,197 @@
/* ****************************************************************************************************** */
/* demo2148_blink_flash.cmd LINKER SCRIPT */
/* */
/* */
/* The Linker Script defines how the code and data emitted by the GNU C compiler and assembler are */
/* to be loaded into memory (code goes into FLASH, variables go into RAM). */
/* */
/* Any symbols defined in the Linker Script are automatically global and available to the rest of the */
/* program. */
/* */
/* To force the linker to use this LINKER SCRIPT, just add the -T demo2148_blink_flash.cmd directive */
/* to the linker flags in the makefile. */
/* */
/* LFLAGS = -Map main.map -nostartfiles -T demo2148_blink_flash.cmd */
/* */
/* */
/* The Philips boot loader supports the ISP (In System Programming) via the serial port and the IAP */
/* (In Application Programming) for flash programming from within your application. */
/* */
/* The boot loader uses RAM memory and we MUST NOT load variables or code in these areas. */
/* */
/* RAM used by boot loader: 0x40000120 - 0x400001FF (223 bytes) for ISP variables */
/* 0x40007FE0 - 0x4000FFFF (32 bytes) for ISP and IAP variables */
/* 0x40007EE0 - 0x40007FE0 (256 bytes) stack for ISP and IAP */
/* */
/* */
/* MEMORY MAP */
/* | |0x40008000 */
/* .-------->|---------------------------------| */
/* . | variables and stack |0x40007FFF */
/* ram_isp_high | for Philips boot loader | */
/* . | 32 + 256 = 288 bytes | */
/* . | | */
/* . | Do not put anything here |0x40007EE0 */
/* .-------->|---------------------------------| */
/* | UDF Stack 4 bytes |0x40007EDC <---------- _stack_end */
/* .-------->|---------------------------------| */
/* | ABT Stack 4 bytes |0x40007ED8 */
/* .-------->|---------------------------------| */
/* | FIQ Stack 4 bytes |0x40007ED4 */
/* .-------->|---------------------------------| */
/* | IRQ Stack 4 bytes |0x40007ED0 */
/* .-------->|---------------------------------| */
/* | SVC Stack 4 bytes |0x40007ECC */
/* .-------->|---------------------------------| */
/* . | |0x40007EC8 */
/* . | stack area for user program | */
/* . | | | */
/* . | | | */
/* . | | | */
/* . | V | */
/* . | | */
/* . | | */
/* . | | */
/* . | free ram | */
/* ram | | */
/* . | | */
/* . | | */
/* . |.................................|0x40000234 <---------- _bss_end */
/* . | | */
/* . | .bss uninitialized variables | */
/* . |.................................|0x40000218 <---------- _bss_start, _edata */
/* . | | */
/* . | .data initialized variables | */
/* . | |0x40000200 <---------- _data */
/* .-------->|---------------------------------| */
/* . | variables used by |0x400001FF */
/* ram_isp_low | Philips boot loader | */
/* . | 223 bytes |0x40000120 */
/* .-------->|---------------------------------| */
/* . | |0x4000011F */
/* ram_vectors | free ram | */
/* . |---------------------------------|0x40000040 */
/* . | |0x4000003F */
/* . | Interrupt Vectors (re-mapped) | */
/* . | 64 bytes |0x40000000 */
/* .-------->|---------------------------------| */
/* | | */
/* */
/* */
/* */
/* | | */
/* .--------> |---------------------------------| */
/* . | |0x0001FFFF */
/* . | | */
/* . | | */
/* . | | */
/* . | | */
/* . | | */
/* . | unused flash eprom | */
/* . | | */
/* . |.................................|0x0000032c */
/* . | | */
/* . | copy of .data area | */
/* flash | | */
/* . |---------------------------------|0x00000314 <----------- _etext */
/* . | | */
/* . | |0x00000180 main */
/* . | |0x00000278 feed */
/* . | main() |0x000002c4 FIQ_Routine */
/* . | |0x000002d8 SWI_Routine */
/* . | |0x000002ec UNDEF_Routine */
/* . | |0x000002b0 IRQ_routine */
/* . |---------------------------------|0x000001cc initialize */
/* . | |0x000000D4 */
/* . | Startup Code | */
/* . | (assembler) | */
/* . | | */
/* . |---------------------------------|0x00000040 Reset_Handler */
/* . | |0x0000003F */
/* . | Interrupt Vector Table (unused) | */
/* . | 64 bytes | */
/* .--------->|---------------------------------|0x00000000 _startup *
/* */
/* */
/* The easy way to prevent the linker from loading anything into a memory area is to define */
/* a MEMORY region for it and then avoid assigning any .text, .data or .bss sections into it. */
/* */
/* */
/* MEMORY */
/* { */
/* ram_isp_low(A) : ORIGIN = 0x40000120, LENGTH = 223 */
/* */
/* } */
/* */
/* */
/* Author: James P. Lynch */
/* */
/* ****************************************************************************************************** */
/* identify the Entry Point */
ENTRY(_startup)
/* specify the LPC2148 memory areas */
MEMORY
{
flash : ORIGIN = 0, LENGTH = 512K /* FLASH ROM */
ram_isp_low(A) : ORIGIN = 0x40000120, LENGTH = 223 /* variables used by Philips ISP bootloader */
ram : ORIGIN = 0x40000200, LENGTH = 32513 /* free RAM area */
ram_isp_high(A) : ORIGIN = 0x40007FE0, LENGTH = 32 /* variables used by Philips ISP bootloader */
ram_usb_dma : ORIGIN = 0x7FD00000, LENGTH = 8192 /* on-chip USB DMA RAM area (not used) */
}
/* define a global symbol _stack_end */
_stack_end = 0x40007EDC;
/* now define the output sections */
SECTIONS
{
. = 0; /* set location counter to address zero */
startup : { *(.startup)} >flash /* the startup code goes into FLASH */
.text : /* collect all sections that should go into FLASH after startup */
{
*(.text) /* all .text sections (code) */
*(.rodata) /* all .rodata sections (constants, strings, etc.) */
*(.rodata*) /* all .rodata* sections (constants, strings, etc.) */
*(.glue_7) /* all .glue_7 sections (no idea what these are) */
*(.glue_7t) /* all .glue_7t sections (no idea what these are) */
_etext = .; /* define a global symbol _etext just after the last code byte */
} >flash /* put all the above into FLASH */
.data : /* collect all initialized .data sections that go into RAM */
{
_data = .; /* create a global symbol marking the start of the .data section */
*(.data) /* all .data sections */
_edata = .; /* define a global symbol marking the end of the .data section */
} >ram AT >flash /* put all the above into RAM (but load the LMA copy into FLASH) */
.bss : /* collect all uninitialized .bss sections that go into RAM */
{
_bss_start = .; /* define a global symbol marking the start of the .bss section */
*(.bss) /* all .bss sections */
} >ram /* put all the above in RAM (it will be cleared in the startup code */
. = ALIGN(4); /* advance location counter to the next 32-bit boundary */
_bss_end = . ; /* define a global symbol marking the end of the .bss section */
}
_end = .; /* define a global symbol marking the end of application RAM */

View File

@ -0,0 +1,265 @@
/*
LPCUSB, an USB device driver for LPC microcontrollers
Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
This is a very simple custom device (not belonging to a specific USB
class). It implements primitive read and write in the ARM memory space.
Each transfer is initiated by a control transfer to inform the device
about the address and size of the following data transfer.
The data transfer takes place over a bulk endpoint (BULK_IN_EP for
reads and BULK_OUT_EP for writes).
This example can be used to measure USB transfer speed.
*/
#include "type.h"
#include "usbdebug.h"
#include "console.h"
#include "usbapi.h"
#include "startup.h"
#define BULK_IN_EP 0x82
#define BULK_OUT_EP 0x05
#define MAX_PACKET_SIZE 64
#define LE_WORD(x) ((x)&0xFF),((x)>>8)
static const U8 abDescriptors[] = {
/* Device descriptor */
0x12,
DESC_DEVICE,
LE_WORD(0x0200), // bcdUSB
0xFF, // bDeviceClass
0x00, // bDeviceSubClass
0x00, // bDeviceProtocol
MAX_PACKET_SIZE0, // bMaxPacketSize
LE_WORD(0xFFFF), // idVendor
LE_WORD(0x0004), // idProduct
LE_WORD(0x0100), // bcdDevice
0x01, // iManufacturer
0x02, // iProduct
0x03, // iSerialNumber
0x01, // bNumConfigurations
// configuration
0x09,
DESC_CONFIGURATION,
LE_WORD(0x20), // wTotalLength
0x01, // bNumInterfaces
0x01, // bConfigurationValue
0x00, // iConfiguration
0x80, // bmAttributes
0x32, // bMaxPower
// interface
0x09,
DESC_INTERFACE,
0x00, // bInterfaceNumber
0x00, // bAlternateSetting
0x02, // bNumEndPoints
0xFF, // bInterfaceClass
0x00, // bInterfaceSubClass
0x00, // bInterfaceProtocol
0x00, // iInterface
// bulk in
0x07,
DESC_ENDPOINT,
BULK_IN_EP, // bEndpointAddress
0x02, // bmAttributes = BULK
LE_WORD(MAX_PACKET_SIZE),// wMaxPacketSize
0, // bInterval
// bulk out
0x07,
DESC_ENDPOINT,
BULK_OUT_EP, // bEndpointAddress
0x02, // bmAttributes = BULK
LE_WORD(MAX_PACKET_SIZE),// wMaxPacketSize
0, // bInterval
// string descriptors
0x04,
DESC_STRING,
LE_WORD(0x0409),
// manufacturer string
0x0E,
DESC_STRING,
'L', 0, 'P', 0, 'C', 0, 'U', 0, 'S', 0, 'B', 0,
// product string
0x1A,
DESC_STRING,
'M', 0, 'e', 0, 'm', 0, 'o', 0, 'r', 0, 'y', 0, 'A', 0, 'c', 0, 'c', 0, 'e', 0, 's', 0, 's', 0,
// serial number string
0x12,
DESC_STRING,
'D', 0, 'E', 0, 'A', 0, 'D', 0, 'C', 0, '0', 0, 'D', 0, 'E', 0,
// terminator
0
};
typedef struct {
U32 dwAddress;
U32 dwLength;
} TMemoryCmd;
static TMemoryCmd MemoryCmd;
static U8 abVendorReqData[sizeof(TMemoryCmd)];
static void _HandleBulkIn(U8 bEP, U8 bEPStatus)
{
int iChunk;
iChunk = MIN(MAX_PACKET_SIZE, MemoryCmd.dwLength);
if (iChunk == 0) {
DBG("_HandleBulkIn done\n");
return;
}
// send next part
USBHwEPWrite(bEP, (U8 *)MemoryCmd.dwAddress, iChunk);
MemoryCmd.dwAddress += iChunk;
MemoryCmd.dwLength -= iChunk;
// limit address range to prevent abort
MemoryCmd.dwAddress &= ~(-512 * 1024);
}
static void _HandleBulkOut(U8 bEP, U8 bEPStatus)
{
int iChunk;
// get next part
iChunk = USBHwEPRead(bEP, NULL, 0);
MemoryCmd.dwAddress += iChunk;
MemoryCmd.dwLength -= iChunk;
if (MemoryCmd.dwLength == 0) {
DBG("_HandleBulkOut done\n");
}
}
/*************************************************************************
HandleVendorRequest
===================
Handles vendor specific requests
Control transfer fields:
* request: 0x01 = prepare memory read
0x02 = prepare memory write
* index: ignored
* value: ignored
* data: U32 dwAddress
U32 dwLength
**************************************************************************/
static BOOL HandleVendorRequest(TSetupPacket *pSetup, int *piLen, U8 **ppbData)
{
TMemoryCmd *pCmd;
pCmd = (TMemoryCmd *)*ppbData;
switch (pSetup->bRequest) {
// prepare read
case 0x01:
MemoryCmd = *pCmd;
DBG("READ: addr=%X, len=%d\n", MemoryCmd.dwAddress, MemoryCmd.dwLength);
// send initial packet
_HandleBulkIn(BULK_IN_EP, 0);
*piLen = 0;
break;
// prepare write
case 0x02:
MemoryCmd = *pCmd;
DBG("WRITE: addr=%X, len=%d\n", MemoryCmd.dwAddress, MemoryCmd.dwLength);
*piLen = 0;
break;
default:
DBG("Unhandled class %X\n", pSetup->bRequest);
return FALSE;
}
return TRUE;
}
#define BAUD_RATE 57600
/*************************************************************************
main
====
**************************************************************************/
int main(void)
{
// PLL and MAM
Initialize();
// init DBG
ConsoleInit(60000000 / (16 * BAUD_RATE));
DBG("Initialising USB stack\n");
// initialise stack
USBInit();
// register device descriptors
USBRegisterDescriptors(abDescriptors);
// override standard request handler
USBRegisterRequestHandler(REQTYPE_TYPE_VENDOR, HandleVendorRequest, abVendorReqData);
// register endpoints
USBHwRegisterEPIntHandler(BULK_IN_EP, _HandleBulkIn);
USBHwRegisterEPIntHandler(BULK_OUT_EP, _HandleBulkOut);
DBG("Starting USB communication\n");
// connect to bus
USBHwConnect(TRUE);
// call USB interrupt handler continuously
while (1) {
USBHwISR();
}
return 0;
}

View File

@ -0,0 +1,268 @@
/*
Copyright 2001, 2002 Georges Menie (www.menie.org)
stdarg version contributed by Christian Ettinger
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
putchar is the only external dependency for this file,
if you have a working putchar, leave it commented out.
If not, uncomment the define below and
replace outbyte(c) by your own function call.
#define putchar(c) outbyte(c)
*/
#include <stdarg.h>
#include "console.h"
static void printchar(char **str, int c)
{
if (str) {
**str = c;
++(*str);
}
else {
putchar(c);
}
}
#define PAD_RIGHT 1
#define PAD_ZERO 2
static int prints(char **out, const char *string, int width, int pad)
{
register int pc = 0, padchar = ' ';
if (width > 0) {
register int len = 0;
register const char *ptr;
for (ptr = string; *ptr; ++ptr) ++len;
if (len >= width) width = 0;
else width -= len;
if (pad & PAD_ZERO) padchar = '0';
}
if (!(pad & PAD_RIGHT)) {
for ( ; width > 0; --width) {
printchar (out, padchar);
++pc;
}
}
for ( ; *string ; ++string) {
printchar (out, *string);
++pc;
}
for ( ; width > 0; --width) {
printchar (out, padchar);
++pc;
}
return pc;
}
/* the following should be enough for 32 bit int */
#define PRINT_BUF_LEN 12
static int printi(char **out, int i, int b, int sg, int width, int pad, int letbase)
{
char print_buf[PRINT_BUF_LEN];
register char *s;
register int t, neg = 0, pc = 0;
register unsigned int u = i;
if (i == 0) {
print_buf[0] = '0';
print_buf[1] = '\0';
return prints (out, print_buf, width, pad);
}
if (sg && b == 10 && i < 0) {
neg = 1;
u = -i;
}
s = print_buf + PRINT_BUF_LEN-1;
*s = '\0';
while (u) {
t = u % b;
if( t >= 10 )
t += letbase - '0' - 10;
*--s = t + '0';
u /= b;
}
if (neg) {
if( width && (pad & PAD_ZERO) ) {
printchar (out, '-');
++pc;
--width;
}
else {
*--s = '-';
}
}
return pc + prints (out, s, width, pad);
}
static int print(char **out, const char *format, va_list args )
{
register int width, pad;
register int pc = 0;
char scr[2];
for (; *format != 0; ++format) {
if (*format == '%') {
++format;
width = pad = 0;
if (*format == '\0') break;
if (*format == '%') goto out;
if (*format == '-') {
++format;
pad = PAD_RIGHT;
}
while (*format == '0') {
++format;
pad |= PAD_ZERO;
}
for ( ; *format >= '0' && *format <= '9'; ++format) {
width *= 10;
width += *format - '0';
}
if( *format == 's' ) {
register char *s = (char *)va_arg( args, int );
pc += prints (out, s?s:"(null)", width, pad);
continue;
}
if( *format == 'd' ) {
pc += printi (out, va_arg( args, int ), 10, 1, width, pad, 'a');
continue;
}
if( *format == 'x' ) {
pc += printi (out, va_arg( args, int ), 16, 0, width, pad, 'a');
continue;
}
if( *format == 'X' ) {
pc += printi (out, va_arg( args, int ), 16, 0, width, pad, 'A');
continue;
}
if( *format == 'u' ) {
pc += printi (out, va_arg( args, int ), 10, 0, width, pad, 'a');
continue;
}
if( *format == 'c' ) {
/* char are converted to int then pushed on the stack */
scr[0] = (char)va_arg( args, int );
scr[1] = '\0';
pc += prints (out, scr, width, pad);
continue;
}
}
else {
out:
printchar (out, *format);
++pc;
}
}
if (out) **out = '\0';
va_end( args );
return pc;
}
int printf(const char *format, ...)
{
va_list args;
va_start( args, format );
return print( 0, format, args );
}
int sprintf(char *out, const char *format, ...)
{
va_list args;
va_start( args, format );
return print( &out, format, args );
}
#ifdef TEST_PRINTF
int main(void)
{
char *ptr = "Hello world!";
char *np = 0;
int i = 5;
unsigned int bs = sizeof(int)*8;
int mi;
char buf[80];
mi = (1 << (bs-1)) + 1;
printf("%s\n", ptr);
printf("printf test\n");
printf("%s is null pointer\n", np);
printf("%d = 5\n", i);
printf("%d = - max int\n", mi);
printf("char %c = 'a'\n", 'a');
printf("hex %x = ff\n", 0xff);
printf("hex %02x = 00\n", 0);
printf("signed %d = unsigned %u = hex %x\n", -3, -3, -3);
printf("%d %s(s)%", 0, "message");
printf("\n");
printf("%d %s(s) with %%\n", 0, "message");
sprintf(buf, "justif: \"%-10s\"\n", "left"); printf("%s", buf);
sprintf(buf, "justif: \"%10s\"\n", "right"); printf("%s", buf);
sprintf(buf, " 3: %04d zero padded\n", 3); printf("%s", buf);
sprintf(buf, " 3: %-4d left justif.\n", 3); printf("%s", buf);
sprintf(buf, " 3: %4d right justif.\n", 3); printf("%s", buf);
sprintf(buf, "-3: %04d zero padded\n", -3); printf("%s", buf);
sprintf(buf, "-3: %-4d left justif.\n", -3); printf("%s", buf);
sprintf(buf, "-3: %4d right justif.\n", -3); printf("%s", buf);
return 0;
}
/*
* if you compile this file with
* gcc -Wall $(YOUR_C_OPTIONS) -DTEST_PRINTF -c printf.c
* you will get a normal warning:
* printf.c:214: warning: spurious trailing `%' in format
* this line is testing an invalid % at the end of the format string.
*
* this should display (on 32bit int machine) :
*
* Hello world!
* printf test
* (null) is null pointer
* 5 = 5
* -2147483647 = - max int
* char a = 'a'
* hex ff = ff
* hex 00 = 00
* signed -3 = unsigned 4294967293 = hex fffffffd
* 0 message(s)
* 0 message(s) with %
* justif: "left "
* justif: " right"
* 3: 0003 zero padded
* 3: 3 left justif.
* 3: 3 right justif.
* -3: -003 zero padded
* -3: -3 left justif.
* -3: -3 right justif.
*/
#endif

View File

@ -0,0 +1,126 @@
/*
Initialisation functions for exception handlers, PLL and MAM
Partially copied from Jim Lynch's tutorial
*/
/**********************************************************
Header files
**********************************************************/
#include "startup.h"
#define MAMCR *(volatile unsigned int *)0xE01FC000
#define MAMTIM *(volatile unsigned int *)0xE01FC004
#define PLLCON *(volatile unsigned int *)0xE01FC080
#define PLLCFG *(volatile unsigned int *)0xE01FC084
#define PLLSTAT *(volatile unsigned int *)0xE01FC088
#define PLLFEED *(volatile unsigned int *)0xE01FC08C
#define VPBDIV *(volatile unsigned int *)0xE01FC100
void IRQ_Routine (void) __attribute__ ((interrupt("IRQ")));
void FIQ_Routine (void) __attribute__ ((interrupt("FIQ")));
void SWI_Routine (void) __attribute__ ((interrupt("SWI")));
void UNDEF_Routine (void) __attribute__ ((interrupt("UNDEF")));
/* Stubs for various interrupts (may be replaced later) */
/* ---------------------------------------------------- */
void IRQ_Routine (void) {
while (1) ;
}
void FIQ_Routine (void) {
while (1) ;
}
void SWI_Routine (void) {
while (1) ;
}
void UNDEF_Routine (void) {
while (1) ;
}
/**********************************************************
Initialize
**********************************************************/
#define PLOCK 0x400
static void feed(void)
{
PLLFEED = 0xAA;
PLLFEED = 0x55;
}
void Initialize(void)
{
// Setting the Phased Lock Loop (PLL)
// ----------------------------------
//
// Olimex LPC-P2148 has a 12.0000 mhz crystal
//
// We'd like the LPC2148 to run at 60 mhz (has to be an even multiple of crystal)
//
// According to the Philips LPC2148 manual: M = cclk / Fosc where: M = PLL multiplier (bits 0-4 of PLLCFG)
// cclk = 60000000 hz
// Fosc = 12000000 hz
//
// Solving: M = 60000000 / 12000000 = 5
//
// Note: M - 1 must be entered into bits 0-4 of PLLCFG (assign 4 to these bits)
//
//
// The Current Controlled Oscilator (CCO) must operate in the range 156 mhz to 320 mhz
//
// According to the Philips LPC2148 manual: Fcco = cclk * 2 * P where: Fcco = CCO frequency
// cclk = 60000000 hz
// P = PLL divisor (bits 5-6 of PLLCFG)
//
// Solving: Fcco = 60000000 * 2 * P
// P = 2 (trial value)
// Fcco = 60000000 * 2 * 2
// Fcc0 = 240000000 hz (good choice for P since it's within the 156 mhz to 320 mhz range)
//
// From Table 22 (page 34) of Philips LPC2148 manual P = 2, PLLCFG bits 5-6 = 1 (assign 1 to these bits)
//
// Finally: PLLCFG = 0 01 00100 = 0x24
//
// Final note: to load PLLCFG register, we must use the 0xAA followed 0x55 write sequence to the PLLFEED register
// this is done in the short function feed() below
//
// Setting Multiplier and Divider values
PLLCFG = 0x24;
feed();
// Enabling the PLL */
PLLCON = 0x1;
feed();
// Wait for the PLL to lock to set frequency
while(!(PLLSTAT & PLOCK)) ;
// Connect the PLL as the clock source
PLLCON = 0x3;
feed();
// Enabling MAM and setting number of clocks used for Flash memory fetch
MAMTIM = 0x3;
MAMCR = 0x2;
// Setting peripheral Clock (pclk) to System Clock (cclk)
VPBDIV = 0x1;
}

View File

@ -0,0 +1,2 @@
void Initialize(void);

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>documents</key>
<array>
<dict>
<key>name</key>
<string>lpcusb</string>
<key>regexFolderFilter</key>
<string>!.*/(\.[^/]*|CVS|_darcs|_MTN|\{arch\}|blib|.*~\.nib|.*\.(framework|app|pbproj|pbxproj|xcode(proj)?|bundle))$</string>
<key>selected</key>
<true/>
<key>sourceDirectory</key>
<string></string>
</dict>
</array>
<key>fileHierarchyDrawerWidth</key>
<integer>200</integer>
<key>metaData</key>
<dict/>
<key>showFileHierarchyDrawer</key>
<false/>
<key>showFileHierarchyPanel</key>
<true/>
<key>treeState</key>
<dict/>
<key>windowFrame</key>
<string>{{0, 58}, {721, 820}}</string>
</dict>
</plist>

View File

@ -0,0 +1,31 @@
/**
@file
primitive types used in the USB stack
(c) 2006, Bertrik Sikken, bertrik@sikken.nl
*/
#ifndef _TYPE_H_
#define _TYPE_H_
typedef unsigned char U8; /**< unsigned 8-bit */
typedef unsigned short int U16; /**< unsigned 16-bit */
typedef unsigned int U32; /**< unsigned 32-bit */
typedef int BOOL; /**< #TRUE or #FALSE */
#define TRUE 1 /**< TRUE */
#define FALSE 0 /**< FALSE */
#ifndef NULL
#define NULL ((void*)0) /**< NULL pointer */
#endif
/* some other useful macros */
#define MIN(x,y) ((x)<(y)?(x):(y)) /**< MIN */
#define MAX(x,y) ((x)>(y)?(x):(y)) /**< MAX */
#endif /* _TYPE_H_ */

View File

@ -0,0 +1,95 @@
/**
(c) 2006, Bertrik Sikken, bertrik@sikken.nl
@file
*/
#include "type.h"
#include "usbstruct.h" // for TSetupPacket
/*************************************************************************
USB configuration
**************************************************************************/
#define MAX_PACKET_SIZE0 64 /**< maximum packet size for EP 0 */
/*************************************************************************
USB hardware interface
**************************************************************************/
// endpoint status sent through callback
#define EP_STATUS_DATA (1<<0) /**< EP has data */
#define EP_STATUS_STALLED (1<<1) /**< EP is stalled */
#define EP_STATUS_SETUP (1<<2) /**< EP received setup packet */
#define EP_STATUS_NACKED (1<<3) /**< EP sent NAK */
#define EP_STATUS_ERROR (1<<4) /**< EP data was overwritten by setup packet */
// device status sent through callback
#define DEV_STATUS_CONNECT (1<<0) /**< device just got connected */
#define DEV_STATUS_SUSPEND (1<<2) /**< device entered suspend state */
#define DEV_STATUS_RESET (1<<4) /**< device just got reset */
// interrupt bits for NACK events in USBHwNakIntEnable
// (these bits conveniently coincide with the LPC214x USB controller bit)
#define INACK_CI (1<<1) /**< interrupt on NACK for control in */
#define INACK_CO (1<<2) /**< interrupt on NACK for control out */
#define INACK_II (1<<3) /**< interrupt on NACK for interrupt in */
#define INACK_IO (1<<4) /**< interrupt on NACK for interrupt out */
#define INACK_BI (1<<5) /**< interrupt on NACK for bulk in */
#define INACK_BO (1<<6) /**< interrupt on NACK for bulk out */
BOOL USBHwInit (void);
void USBHwISR (void);
void USBHwNakIntEnable (U8 bIntBits);
void USBHwConnect (BOOL fConnect);
void USBHwSetAddress (U8 bAddr);
void USBHwConfigDevice (BOOL fConfigured);
// endpoint operations
void USBHwEPConfig (U8 bEP, U16 wMaxPacketSize);
int USBHwEPRead (U8 bEP, U8 *pbBuf, int iMaxLen);
int USBHwEPWrite (U8 bEP, U8 *pbBuf, int iLen);
void USBHwEPStall (U8 bEP, BOOL fStall);
BOOL USBHwEPIsStalled (U8 bEP);
/** Endpoint interrupt handler callback */
typedef void (TFnEPIntHandler) (U8 bEP, U8 bEPStatus);
void USBHwRegisterEPIntHandler (U8 bEP, TFnEPIntHandler *pfnHandler);
/** Device status handler callback */
typedef void (TFnDevIntHandler) (U8 bDevStatus);
void USBHwRegisterDevIntHandler (TFnDevIntHandler *pfnHandler);
/** Frame event handler callback */
typedef void (TFnFrameHandler)(U16 wFrame);
void USBHwRegisterFrameHandler(TFnFrameHandler *pfnHandler);
/*************************************************************************
USB application interface
**************************************************************************/
// initialise the complete stack, including HW
BOOL USBInit(void);
/** Request handler callback (standard, vendor, class) */
typedef BOOL (TFnHandleRequest)(TSetupPacket *pSetup, int *piLen, U8 **ppbData);
void USBRegisterRequestHandler(int iType, TFnHandleRequest *pfnHandler, U8 *pbDataStore);
void USBRegisterCustomReqHandler(TFnHandleRequest *pfnHandler);
/** Descriptor handler callback */
typedef BOOL (TFnGetDescriptor)(U16 wTypeIndex, U16 wLangID, int *piLen, U8 **ppbData);
/** Default standard request handler */
BOOL USBHandleStandardRequest(TSetupPacket *pSetup, int *piLen, U8 **ppbData);
/** Default EP0 handler */
void USBHandleControlTransfer(U8 bEP, U8 bEPStat);
/** Descriptor handling */
void USBRegisterDescriptors(const U8 *pabDescriptors);
BOOL USBGetDescriptor(U16 wTypeIndex, U16 wLangID, int *piLen, U8 **ppbData);

View File

@ -0,0 +1,222 @@
/*
LPCUSB, an USB device driver for LPC microcontrollers
Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/** @file
Control transfer handler.
In case of a control-write (host-to-device), this module collects the full
control message in a local buffer, then sends it off to an installed
request handler.
In case of a control-read (device-to-host), an installed request handler
is asked to handle the request and provide return data. The handler can
either put the data in the control data buffer through the supplied pointer,
or it can supply a new data pointer. In both cases, the handler is required
to update the data length in *piLen;
Currently, control transfers are handled in a very simple way, keeping
almost no state about the control transfer progress (setup stage, data
stage, status stage). We simply follow the host: if it sends data, we store
it in the control data buffer and if it asks for data, we just send the next
block.
*/
#include "type.h"
#include "usbdebug.h"
#include "usbstruct.h"
#include "usbapi.h"
#define MAX_CONTROL_SIZE 128 /**< maximum total size of control transfer data */
#define MAX_REQ_HANDLERS 4 /**< standard, class, vendor, reserved */
static TSetupPacket Setup; /**< setup packet */
static U8 *pbData; /**< pointer to data buffer */
static int iResidue; /**< remaining bytes in buffer */
static int iLen; /**< total length of control transfer */
/** Array of installed request handler callbacks */
static TFnHandleRequest *apfnReqHandlers[4] = {NULL, NULL, NULL, NULL};
/** Array of installed request data pointers */
static U8 *apbDataStore[4] = {NULL, NULL, NULL, NULL};
/**
Local function to handle a request by calling one of the installed
request handlers.
In case of data going from host to device, the data is at *ppbData.
In case of data going from device to host, the handler can either
choose to write its data at *ppbData or update the data pointer.
@param [in] pSetup The setup packet
@param [in,out] *piLen Pointer to data length
@param [in,out] ppbData Data buffer.
@return TRUE if the request was handles successfully
*/
static BOOL _HandleRequest(TSetupPacket *pSetup, int *piLen, U8 **ppbData)
{
TFnHandleRequest *pfnHandler;
int iType;
iType = REQTYPE_GET_TYPE(pSetup->bmRequestType);
pfnHandler = apfnReqHandlers[iType];
if (pfnHandler == NULL) {
DBG("No handler for reqtype %d\n", iType);
return FALSE;
}
return pfnHandler(pSetup, piLen, ppbData);
}
/**
Local function to stall the control endpoint
@param [in] bEPStat Endpoint status
*/
static void StallControlPipe(U8 bEPStat)
{
U8 *pb;
int i;
USBHwEPStall(0x80, TRUE);
// dump setup packet
DBG("STALL on [");
pb = (U8 *)&Setup;
for (i = 0; i < 8; i++) {
DBG(" %02x", *pb++);
}
DBG("] stat=%x\n", bEPStat);
}
/**
Sends next chunk of data (possibly 0 bytes) to host
*/
static void DataIn(void)
{
int iChunk;
iChunk = MIN(MAX_PACKET_SIZE0, iResidue);
USBHwEPWrite(0x80, pbData, iChunk);
pbData += iChunk;
iResidue -= iChunk;
}
/**
* Handles IN/OUT transfers on EP0
*
* @param [in] bEP Endpoint address
* @param [in] bEPStat Endpoint status
*/
void USBHandleControlTransfer(U8 bEP, U8 bEPStat)
{
int iChunk, iType;
if (bEP == 0x00) {
// OUT transfer
if (bEPStat & EP_STATUS_SETUP) {
// setup packet, reset request message state machine
USBHwEPRead(0x00, (U8 *)&Setup, sizeof(Setup));
DBG("S%x", Setup.bRequest);
// defaults for data pointer and residue
iType = REQTYPE_GET_TYPE(Setup.bmRequestType);
pbData = apbDataStore[iType];
iResidue = Setup.wLength;
iLen = Setup.wLength;
if ((Setup.wLength == 0) ||
(REQTYPE_GET_DIR(Setup.bmRequestType) == REQTYPE_DIR_TO_HOST)) {
// ask installed handler to process request
if (!_HandleRequest(&Setup, &iLen, &pbData)) {
DBG("_HandleRequest1 failed\n");
StallControlPipe(bEPStat);
return;
}
// send smallest of requested and offered length
iResidue = MIN(iLen, Setup.wLength);
// send first part (possibly a zero-length status message)
DataIn();
}
}
else {
if (iResidue > 0) {
// store data
iChunk = USBHwEPRead(0x00, pbData, iResidue);
if (iChunk < 0) {
StallControlPipe(bEPStat);
return;
}
pbData += iChunk;
iResidue -= iChunk;
if (iResidue == 0) {
// received all, send data to handler
iType = REQTYPE_GET_TYPE(Setup.bmRequestType);
pbData = apbDataStore[iType];
if (!_HandleRequest(&Setup, &iLen, &pbData)) {
DBG("_HandleRequest2 failed\n");
StallControlPipe(bEPStat);
return;
}
// send status to host
DataIn();
}
}
else {
// absorb zero-length status message
iChunk = USBHwEPRead(0x00, NULL, 0);
DBG(iChunk > 0 ? "?" : "");
}
}
}
else if (bEP == 0x80) {
// IN transfer
// send more data if available (possibly a 0-length packet)
DataIn();
}
else {
ASSERT(FALSE);
}
}
/**
Registers a callback for handling requests
@param [in] iType Type of request, e.g. REQTYPE_TYPE_STANDARD
@param [in] *pfnHandler Callback function pointer
@param [in] *pbDataStore Data storage area for this type of request
*/
void USBRegisterRequestHandler(int iType, TFnHandleRequest *pfnHandler, U8 *pbDataStore)
{
ASSERT(iType >= 0);
ASSERT(iType < 4);
apfnReqHandlers[iType] = pfnHandler;
apbDataStore[iType] = pbDataStore;
}

View File

@ -0,0 +1,12 @@
int printf(const char *format, ...);
#ifdef DEBUG
#define DBG printf
#define ASSERT(x) if(!(x)){DBG("\nAssertion '%s' failed in %s:%s#%d!\n",#x,__FILE__,__FUNCTION__,__LINE__);while(1);}
#else
#define DBG(x ...)
#define ASSERT(x)
#endif

View File

@ -0,0 +1,541 @@
/*
LPCUSB, an USB device driver for LPC microcontrollers
Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/** @file
USB hardware layer
*/
#include "type.h"
#include "usbdebug.h"
#include "usbhw_lpc.h"
#include "usbapi.h"
#ifdef DEBUG
// comment out the following line if you don't want to use debug LEDs
#define DEBUG_LED
#endif
#ifdef DEBUG_LED
#define DEBUG_LED_ON(x) IOCLR0 = (1 << x);
#define DEBUG_LED_OFF(x) IOSET0 = (1 << x);
#define DEBUG_LED_INIT(x) PINSEL0 &= ~(0x3 << (2*x)); IODIR0 |= (1 << x); DEBUG_LED_OFF(x);
#else
#define DEBUG_LED_INIT(x) /**< LED initialisation macro */
#define DEBUG_LED_ON(x) /**< turn LED on */
#define DEBUG_LED_OFF(x) /**< turn LED off */
#endif
/** Installed device interrupt handler */
static TFnDevIntHandler *_pfnDevIntHandler = NULL;
/** Installed endpoint interrupt handlers */
static TFnEPIntHandler *_apfnEPIntHandlers[16];
/** Installed frame interrupt handlers */
static TFnFrameHandler *_pfnFrameHandler = NULL;
/** convert from endpoint address to endpoint index */
#define EP2IDX(bEP) ((((bEP)&0xF)<<1)|(((bEP)&0x80)>>7))
/** convert from endpoint index to endpoint address */
#define IDX2EP(idx) ((((idx)<<7)&0x80)|(((idx)>>1)&0xF))
/**
Local function to wait for a device interrupt (and clear it)
@param [in] dwIntr Interrupts to wait for
*/
static void Wait4DevInt(U32 dwIntr)
{
while ((USBDevIntSt & dwIntr) != dwIntr);
USBDevIntClr = dwIntr;
}
/**
Local function to send a command to the USB protocol engine
@param [in] bCmd Command to send
*/
static void USBHwCmd(U8 bCmd)
{
// clear CDFULL/CCEMTY
USBDevIntClr = CDFULL | CCEMTY;
// write command code
USBCmdCode = 0x00000500 | (bCmd << 16);
Wait4DevInt(CCEMTY);
}
/**
Local function to send a command + data to the USB protocol engine
@param [in] bCmd Command to send
@param [in] bData Data to send
*/
static void USBHwCmdWrite(U8 bCmd, U16 bData)
{
// write command code
USBHwCmd(bCmd);
// write command data
USBCmdCode = 0x00000100 | (bData << 16);
Wait4DevInt(CCEMTY);
}
/**
Local function to send a command to the USB protocol engine and read data
@param [in] bCmd Command to send
@return the data
*/
static U8 USBHwCmdRead(U8 bCmd)
{
// write command code
USBHwCmd(bCmd);
// get data
USBCmdCode = 0x00000200 | (bCmd << 16);
Wait4DevInt(CDFULL);
return USBCmdData;
}
/**
'Realizes' an endpoint, meaning that buffer space is reserved for
it. An endpoint needs to be realised before it can be used.
From experiments, it appears that a USB reset causes USBReEP to
re-initialise to 3 (= just the control endpoints).
However, a USB bus reset does not disturb the USBMaxPSize settings.
@param [in] idx Endpoint index
@param [in] wMaxPSize Maximum packet size for this endpoint
*/
static void USBHwEPRealize(int idx, U16 wMaxPSize)
{
USBReEP |= (1 << idx);
USBEpInd = idx;
USBMaxPSize = wMaxPSize;
Wait4DevInt(EP_RLZED);
}
/**
Enables or disables an endpoint
@param [in] idx Endpoint index
@param [in] fEnable TRUE to enable, FALSE to disable
*/
static void USBHwEPEnable(int idx, BOOL fEnable)
{
USBHwCmdWrite(CMD_EP_SET_STATUS | idx, fEnable ? 0 : EP_DA);
}
/**
Configures an endpoint and enables it
@param [in] bEP Endpoint number
@param [in] wMaxPacketSize Maximum packet size for this EP
*/
void USBHwEPConfig(U8 bEP, U16 wMaxPacketSize)
{
int idx;
idx = EP2IDX(bEP);
// realise EP
USBHwEPRealize(idx, wMaxPacketSize);
// enable EP
USBHwEPEnable(idx, TRUE);
}
/**
Registers an endpoint event callback
@param [in] bEP Endpoint number
@param [in] pfnHandler Callback function
*/
void USBHwRegisterEPIntHandler(U8 bEP, TFnEPIntHandler *pfnHandler)
{
int idx;
idx = EP2IDX(bEP);
ASSERT(idx<32);
/* add handler to list of EP handlers */
_apfnEPIntHandlers[idx / 2] = pfnHandler;
/* enable EP interrupt */
USBEpIntEn |= (1 << idx);
USBDevIntEn |= EP_SLOW;
DBG("Registered handler for EP 0x%x\n", bEP);
}
/**
Registers an device status callback
@param [in] pfnHandler Callback function
*/
void USBHwRegisterDevIntHandler(TFnDevIntHandler *pfnHandler)
{
_pfnDevIntHandler = pfnHandler;
// enable device interrupt
USBDevIntEn |= DEV_STAT;
DBG("Registered handler for device status\n");
}
/**
Registers the frame callback
@param [in] pfnHandler Callback function
*/
void USBHwRegisterFrameHandler(TFnFrameHandler *pfnHandler)
{
_pfnFrameHandler = pfnHandler;
// enable device interrupt
USBDevIntEn |= FRAME;
DBG("Registered handler for frame\n");
}
/**
Sets the USB address.
@param [in] bAddr Device address to set
*/
void USBHwSetAddress(U8 bAddr)
{
USBHwCmdWrite(CMD_DEV_SET_ADDRESS, DEV_EN | bAddr);
}
/**
Connects or disconnects from the USB bus
@param [in] fConnect If TRUE, connect, otherwise disconnect
*/
void USBHwConnect(BOOL fConnect)
{
USBHwCmdWrite(CMD_DEV_STATUS, fConnect ? CON : 0);
}
/**
Enables interrupt on NAK condition
For IN endpoints a NAK is generated when the host wants to read data
from the device, but none is available in the endpoint buffer.
For OUT endpoints a NAK is generated when the host wants to write data
to the device, but the endpoint buffer is still full.
The endpoint interrupt handlers can distinguish regular (ACK) interrupts
from NAK interrupt by checking the bits in their bEPStatus argument.
@param [in] bIntBits Bitmap indicating which NAK interrupts to enable
*/
void USBHwNakIntEnable(U8 bIntBits)
{
USBHwCmdWrite(CMD_DEV_SET_MODE, bIntBits);
}
/**
Gets the stalled property of an endpoint
@param [in] bEP Endpoint number
@return TRUE if stalled, FALSE if not stalled
*/
BOOL USBHwEPIsStalled(U8 bEP)
{
int idx = EP2IDX(bEP);
return (USBHwCmdRead(CMD_EP_SELECT | idx) & 2);
}
/**
Sets the stalled property of an endpoint
@param [in] bEP Endpoint number
@param [in] fStall TRUE to stall, FALSE to unstall
*/
void USBHwEPStall(U8 bEP, BOOL fStall)
{
int idx = EP2IDX(bEP);
USBHwCmdWrite(CMD_EP_SET_STATUS | idx, fStall ? EP_ST : 0);
}
/**
Writes data to an endpoint buffer
@param [in] bEP Endpoint number
@param [in] pbBuf Endpoint data
@param [in] iLen Number of bytes to write
@return TRUE if the data was successfully written or <0 in case of error.
*/
int USBHwEPWrite(U8 bEP, U8 *pbBuf, int iLen)
{
int idx;
idx = EP2IDX(bEP);
// DBG("<%d", iLen);
// DBG("<");
// set write enable for specific endpoint
USBCtrl = WR_EN | ((bEP & 0xF) << 2);
// set packet length
USBTxPLen = iLen;
// write data
while (USBCtrl & WR_EN) {
USBTxData = (pbBuf[3] << 24) | (pbBuf[2] << 16) | (pbBuf[1] << 8) | pbBuf[0];
pbBuf += 4;
}
// select endpoint and validate buffer
USBHwCmd(CMD_EP_SELECT | idx);
USBHwCmd(CMD_EP_VALIDATE_BUFFER);
return iLen;
}
/**
Reads data from an endpoint buffer
@param [in] bEP Endpoint number
@param [in] pbBuf Endpoint data
@param [in] iMaxLen Maximum number of bytes to read
@return the number of bytes available in the EP (possibly more than iMaxLen),
or <0 in case of error.
*/
int USBHwEPRead(U8 bEP, U8 *pbBuf, int iMaxLen)
{
int i, idx;
U32 dwData, dwLen;
idx = EP2IDX(bEP);
// set read enable bit for specific endpoint
USBCtrl = RD_EN | ((bEP & 0xF) << 2);
// wait for PKT_RDY
do {
dwLen = USBRxPLen;
} while ((dwLen & PKT_RDY) == 0);
// packet valid?
if ((dwLen & DV) == 0) {
return -1;
}
// get length
dwLen &= PKT_LNGTH_MASK;
// get data
while (USBCtrl & RD_EN) {
dwData = USBRxData;
if (pbBuf != NULL) {
for (i = 0; i < 4; i++) {
if (iMaxLen-- != 0) {
*pbBuf++ = dwData & 0xFF;
}
dwData >>= 8;
}
}
}
// select endpoint and clear buffer
USBHwCmd(CMD_EP_SELECT | idx);
USBHwCmd(CMD_EP_CLEAR_BUFFER);
// DBG(">%d", dwLen);
// DBG(">");
return dwLen;
}
/**
Sets the 'configured' state.
All registered endpoints are 'realised' and enabled, and the
'configured' bit is set in the device status register.
@param [in] fConfigured If TRUE, configure device, else unconfigure
*/
void USBHwConfigDevice(BOOL fConfigured)
{
// set configured bit
USBHwCmdWrite(CMD_DEV_CONFIG, fConfigured ? CONF_DEVICE : 0);
}
/**
USB interrupt handler
Endpoint interrupts are mapped to the slow interrupt
*/
void USBHwISR(void)
{
U32 dwStatus, dwEPIntStat;
U32 dwIntBit;
U8 bEPStat, bDevStat, bStat;
int i;
dwStatus = USBDevIntSt;
// handle device dwStatus interrupts
if (dwStatus & DEV_STAT) {
DEBUG_LED_ON(8);
bDevStat = USBHwCmdRead(CMD_DEV_STATUS);
if (bDevStat & (CON_CH | SUS_CH | RST)) {
// convert device status into something HW independent
bStat = ((bDevStat & CON) ? DEV_STATUS_CONNECT : 0) |
((bDevStat & SUS) ? DEV_STATUS_SUSPEND : 0) |
((bDevStat & RST) ? DEV_STATUS_RESET : 0);
// call handler
if (_pfnDevIntHandler != NULL) {
_pfnDevIntHandler(bStat);
}
}
// clear DEV_STAT;
USBDevIntClr = DEV_STAT;
DEBUG_LED_OFF(8);
}
// check endpoint interrupts
if (dwStatus & EP_SLOW) {
DEBUG_LED_ON(9);
dwEPIntStat = USBEpIntSt;
for (i = 0; i < 32; i++) {
dwIntBit = (1 << i);
if (dwEPIntStat & dwIntBit) {
// clear int (and retrieve status)
USBEpIntClr = dwIntBit;
Wait4DevInt(CDFULL);
bEPStat = USBCmdData;
// convert EP pipe stat into something HW independent
bStat = ((bEPStat & EPSTAT_FE) ? EP_STATUS_DATA : 0) |
((bEPStat & EPSTAT_ST) ? EP_STATUS_STALLED : 0) |
((bEPStat & EPSTAT_STP) ? EP_STATUS_SETUP : 0) |
((bEPStat & EPSTAT_EPN) ? EP_STATUS_NACKED : 0) |
((bEPStat & EPSTAT_PO) ? EP_STATUS_ERROR : 0);
// call handler
if (_apfnEPIntHandlers[i / 2] != NULL) {
_apfnEPIntHandlers[i / 2](IDX2EP(i), bStat);
}
}
}
// clear EP_SLOW
USBDevIntClr = EP_SLOW;
DEBUG_LED_OFF(9);
}
// handle frame interrupt
if (dwStatus & FRAME) {
DEBUG_LED_ON(10);
if (_pfnFrameHandler != NULL) {
_pfnFrameHandler(0); // implement counter later
}
// clear int
USBDevIntClr = FRAME;
DEBUG_LED_OFF(10);
}
}
/**
Initialises the USB hardware
This function assumes that the hardware is connected as shown in
section 10.1 of the LPC2148 data sheet:
* P0.31 controls a switch to connect a 1.5k pull-up to D+ if low.
* P0.23 is connected to USB VCC.
Embedded artists board: make sure to disconnect P0.23 LED as it
acts as a pull-up and so prevents detection of USB disconnect.
@return TRUE if the hardware was successfully initialised
*/
BOOL USBHwInit(void)
{
// configure P0.23 for Vbus sense
PINSEL1 = (PINSEL1 & ~(3 << 14)) | (1 << 14); // P0.23
IODIR0 &= ~(1 << 23);
// configure P0.31 for CONNECT
PINSEL1 = (PINSEL1 & ~(3 << 30)) | (2 << 30); // P0.31
// enable PUSB
PCONP |= (1 << 31);
// initialise PLL
PLL1CON = 1; // enable PLL
PLL1CFG = (1 << 5) | 3; // P = 2, M = 4
PLL1FEED = 0xAA;
PLL1FEED = 0x55;
while ((PLL1STAT & (1 << 10)) == 0);
PLL1CON = 3; // enable and connect
PLL1FEED = 0xAA;
PLL1FEED = 0x55;
// disable/clear all interrupts for now
USBDevIntEn = 0;
USBEpIntEn = 0;
USBDevIntClr = 0xFFFFFFFF;
USBEpIntClr = 0xFFFFFFFF;
// setup control endpoints
USBHwEPConfig(0x00, MAX_PACKET_SIZE0);
USBHwEPConfig(0x80, MAX_PACKET_SIZE0);
// by default, only ACKs generate interrupts
USBHwNakIntEnable(0);
// init debug leds
DEBUG_LED_INIT(8);
DEBUG_LED_INIT(9);
DEBUG_LED_INIT(10);
return TRUE;
}

View File

@ -0,0 +1,156 @@
/**
(c) 2006, Bertrik Sikken, bertrik@sikken.nl
Hardware definitions for the LPC214x USB controller
These are private to the usbhw module
*/
/* Common LPC2148 definitions, related to USB */
#define PCONP *(volatile unsigned int *)0xE01FC0C4
#define PLL1CON *(volatile unsigned int *)0xE01FC0A0
#define PLL1CFG *(volatile unsigned int *)0xE01FC0A4
#define PLL1STAT *(volatile unsigned int *)0xE01FC0A8
#define PLL1FEED *(volatile unsigned int *)0xE01FC0AC
#define PINSEL0 *(volatile unsigned int *)0xE002C000
#define PINSEL1 *(volatile unsigned int *)0xE002C004
#define IOPIN0 *(volatile unsigned int *)0xE0028000
#define IOSET0 *(volatile unsigned int *)0xE0028004
#define IODIR0 *(volatile unsigned int *)0xE0028008
#define IOCLR0 *(volatile unsigned int *)0xE002800C
/* USB register definitions */
#define USBIntSt *(volatile unsigned int *)0xE01FC1C0
#define USBDevIntSt *(volatile unsigned int *)0xE0090000
#define USBDevIntEn *(volatile unsigned int *)0xE0090004
#define USBDevIntClr *(volatile unsigned int *)0xE0090008
#define USBDevIntSet *(volatile unsigned int *)0xE009000C
#define USBDevIntPri *(volatile unsigned int *)0xE009002C
#define USBEpIntSt *(volatile unsigned int *)0xE0090030
#define USBEpIntEn *(volatile unsigned int *)0xE0090034
#define USBEpIntClr *(volatile unsigned int *)0xE0090038
#define USBEpIntSet *(volatile unsigned int *)0xE009003C
#define USBEpIntPri *(volatile unsigned int *)0xE0090040
#define USBReEP *(volatile unsigned int *)0xE0090044
#define USBEpInd *(volatile unsigned int *)0xE0090048
#define USBMaxPSize *(volatile unsigned int *)0xE009004C
#define USBRxData *(volatile unsigned int *)0xE0090018
#define USBRxPLen *(volatile unsigned int *)0xE0090020
#define USBTxData *(volatile unsigned int *)0xE009001C
#define USBTxPLen *(volatile unsigned int *)0xE0090024
#define USBCtrl *(volatile unsigned int *)0xE0090028
#define USBCmdCode *(volatile unsigned int *)0xE0090010
#define USBCmdData *(volatile unsigned int *)0xE0090014
/* USBIntSt bits */
#define USB_INT_REQ_LP (1<<0)
#define USB_INT_REQ_HP (1<<1)
#define USB_INT_REQ_DMA (1<<2)
#define USB_need_clock (1<<8)
#define EN_USB_BITS (1<<31)
/* USBDevInt... bits */
#define FRAME (1<<0)
#define EP_FAST (1<<1)
#define EP_SLOW (1<<2)
#define DEV_STAT (1<<3)
#define CCEMTY (1<<4)
#define CDFULL (1<<5)
#define RxENDPKT (1<<6)
#define TxENDPKT (1<<7)
#define EP_RLZED (1<<8)
#define ERR_INT (1<<9)
/* USBRxPLen bits */
#define PKT_LNGTH (1<<0)
#define PKT_LNGTH_MASK 0x3FF
#define DV (1<<10)
#define PKT_RDY (1<<11)
/* USBCtrl bits */
#define RD_EN (1<<0)
#define WR_EN (1<<1)
#define LOG_ENDPOINT (1<<2)
/* protocol engine command codes */
/* device commands */
#define CMD_DEV_SET_ADDRESS 0xD0
#define CMD_DEV_CONFIG 0xD8
#define CMD_DEV_SET_MODE 0xF3
#define CMD_DEV_READ_CUR_FRAME_NR 0xF5
#define CMD_DEV_READ_TEST_REG 0xFD
#define CMD_DEV_STATUS 0xFE /* read/write */
#define CMD_DEV_GET_ERROR_CODE 0xFF
#define CMD_DEV_READ_ERROR_STATUS 0xFB
/* endpoint commands */
#define CMD_EP_SELECT 0x00
#define CMD_EP_SELECT_CLEAR 0x40
#define CMD_EP_SET_STATUS 0x40
#define CMD_EP_CLEAR_BUFFER 0xF2
#define CMD_EP_VALIDATE_BUFFER 0xFA
/* set address command */
#define DEV_ADDR (1<<0)
#define DEV_EN (1<<7)
/* configure device command */
#define CONF_DEVICE (1<<0)
/* set mode command */
#define AP_CLK (1<<0)
#define INAK_CI (1<<1)
#define INAK_CO (1<<2)
#define INAK_II (1<<3)
#define INAK_IO (1<<4)
#define INAK_BI (1<<5)
#define INAK_BO (1<<6)
/* set get device status command */
#define CON (1<<0)
#define CON_CH (1<<1)
#define SUS (1<<2)
#define SUS_CH (1<<3)
#define RST (1<<4)
/* get error code command */
// ...
/* Select Endpoint command read bits */
#define EPSTAT_FE (1<<0)
#define EPSTAT_ST (1<<1)
#define EPSTAT_STP (1<<2)
#define EPSTAT_PO (1<<3)
#define EPSTAT_EPN (1<<4)
#define EPSTAT_B1FULL (1<<5)
#define EPSTAT_B2FULL (1<<6)
/* CMD_EP_SET_STATUS command */
#define EP_ST (1<<0)
#define EP_DA (1<<5)
#define EP_RF_MO (1<<6)
#define EP_CND_ST (1<<7)
/* read error status command */
#define PID_ERR (1<<0)
#define UEPKT (1<<1)
#define DCRC (1<<2)
#define TIMEOUT (1<<3)
#define EOP (1<<4)
#define B_OVRN (1<<5)
#define BTSTF (1<<6)
#define TGL_ERR (1<<7)

View File

@ -0,0 +1,69 @@
/*
LPCUSB, an USB device driver for LPC microcontrollers
Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/** @file
USB stack initialisation
*/
#include "type.h"
#include "usbdebug.h"
#include "usbapi.h"
/** data storage area for standard requests */
static U8 abStdReqData[8];
/**
USB reset handler
@param [in] bDevStatus Device status
*/
static void HandleUsbReset(U8 bDevStatus)
{
if (bDevStatus & DEV_STATUS_RESET) {
DBG("\n!");
}
}
/**
Initialises the USB hardware and sets up the USB stack by
installing default callbacks.
@return TRUE if initialisation was successful
*/
BOOL USBInit(void)
{
// init hardware
USBHwInit();
// register bus reset handler
USBHwRegisterDevIntHandler(HandleUsbReset);
// register control transfer handler on EP0
USBHwRegisterEPIntHandler(0x00, USBHandleControlTransfer);
USBHwRegisterEPIntHandler(0x80, USBHandleControlTransfer);
// register standard request handler
USBRegisterRequestHandler(REQTYPE_TYPE_STANDARD, USBHandleStandardRequest, abStdReqData);
return TRUE;
}

View File

@ -0,0 +1,415 @@
/*
LPCUSB, an USB device driver for LPC microcontrollers
Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/** @file
Standard request handler.
This modules handles the 'chapter 9' processing, specifically the
standard device requests in table 9-3 from the universal serial bus
specification revision 2.0
Specific types of devices may specify additional requests (for example
HID devices add a GET_DESCRIPTOR request for interfaces), but they
will not be part of this module.
@todo some requests have to return a request error if device not configured:
@todo GET_INTERFACE, GET_STATUS, SET_INTERFACE, SYNCH_FRAME
@todo this applies to the following if endpoint != 0:
@todo SET_FEATURE, GET_FEATURE
*/
#include "type.h"
#include "usbdebug.h"
#include "usbstruct.h"
#include "usbapi.h"
#define MAX_DESC_HANDLERS 4 /**< device, interface, endpoint, other */
/* general descriptor field offsets */
#define DESC_bLength 0 /**< length offset */
#define DESC_bDescriptorType 1 /**< descriptor type offset */
/* config descriptor field offsets */
#define CONF_DESC_wTotalLength 2 /**< total length offset */
#define CONF_DESC_bConfigurationValue 5 /**< configuration value offset */
/* interface descriptor field offsets */
#define INTF_DESC_bAlternateSetting 3 /**< alternate setting offset */
/* endpoint descriptor field offsets */
#define ENDP_DESC_bEndpointAddress 2 /**< endpoint address offset */
#define ENDP_DESC_wMaxPacketSize 4 /**< maximum packet size offset */
/** Currently selected configuration */
static U8 bConfiguration = 0;
/** Installed custom request handler */
static TFnHandleRequest *pfnHandleCustomReq = NULL;
/** Pointer to registered descriptors */
static const U8 *pabDescrip = NULL;
/**
Registers a pointer to a descriptor block containing all descriptors
for the device.
@param [in] pabDescriptors The descriptor byte array
*/
void USBRegisterDescriptors(const U8 *pabDescriptors)
{
pabDescrip = pabDescriptors;
}
/**
Parses the list of installed USB descriptors and attempts to find
the specified USB descriptor.
@param [in] wTypeIndex Type and index of the descriptor
@param [in] wLangID Language ID of the descriptor (currently unused)
@param [out] *piLen Descriptor length
@param [out] *ppbData Descriptor data
@return TRUE if the descriptor was found, FALSE otherwise
*/
BOOL USBGetDescriptor(U16 wTypeIndex, U16 wLangID, int *piLen, U8 **ppbData)
{
U8 bType, bIndex;
U8 *pab;
int iCurIndex;
ASSERT(pabDescrip != NULL);
bType = GET_DESC_TYPE(wTypeIndex);
bIndex = GET_DESC_INDEX(wTypeIndex);
pab = (U8 *)pabDescrip;
iCurIndex = 0;
while (pab[DESC_bLength] != 0) {
if (pab[DESC_bDescriptorType] == bType) {
if (iCurIndex == bIndex) {
// set data pointer
*ppbData = pab;
// get length from structure
if (bType == DESC_CONFIGURATION) {
// configuration descriptor is an exception, length is at offset 2 and 3
*piLen = (pab[CONF_DESC_wTotalLength]) |
(pab[CONF_DESC_wTotalLength + 1] << 8);
}
else {
// normally length is at offset 0
*piLen = pab[0];
}
return TRUE;
}
iCurIndex++;
}
// skip to next descriptor
pab += pab[DESC_bLength];
}
// nothing found
DBG("Desc %x not found!\n", wTypeIndex);
return FALSE;
}
/**
Configures the device according to the specified configuration index and
alternate setting by parsing the installed USB descriptor list.
A configuration index of 0 unconfigures the device.
@param [in] bConfigIndex Configuration index
@param [in] bAltSetting Alternate setting number
@todo function always returns TRUE, add stricter checking?
@return TRUE if successfully configured, FALSE otherwise
*/
static BOOL USBSetConfiguration(U8 bConfigIndex, U8 bAltSetting)
{
U8 *pab;
U8 bCurConfig, bCurAltSetting;
U8 bEP;
U16 wMaxPktSize;
ASSERT(pabDescrip != NULL);
// parse installed USB descriptors to configure endpoints
pab = (U8 *)pabDescrip;
bCurConfig = 0xFF;
bCurAltSetting = 0xFF;
while (pab[DESC_bLength] != 0) {
switch (pab[DESC_bDescriptorType]) {
case DESC_CONFIGURATION:
// remember current configuration index
bCurConfig = pab[CONF_DESC_bConfigurationValue];
break;
case DESC_INTERFACE:
// remember current alternate setting
bCurAltSetting = pab[INTF_DESC_bAlternateSetting];
break;
case DESC_ENDPOINT:
if ((bCurConfig == bConfigIndex) &&
(bCurAltSetting == bAltSetting)) {
// endpoint found for desired config and alternate setting
bEP = pab[ENDP_DESC_bEndpointAddress];
wMaxPktSize = (pab[ENDP_DESC_wMaxPacketSize]) |
(pab[ENDP_DESC_wMaxPacketSize + 1] << 8);
// configure it
USBHwEPConfig(bEP, wMaxPktSize);
}
break;
default:
break;
}
// skip to next descriptor
pab += pab[DESC_bLength];
}
// configure device
USBHwConfigDevice(bConfigIndex != 0);
return TRUE;
}
/**
Local function to handle a standard device request
@param [in] pSetup The setup packet
@param [in,out] *piLen Pointer to data length
@param [in,out] ppbData Data buffer.
@return TRUE if the request was handled successfully
*/
static BOOL HandleStdDeviceReq(TSetupPacket *pSetup, int *piLen, U8 **ppbData)
{
U8 *pbData = *ppbData;
switch (pSetup->bRequest) {
case REQ_GET_STATUS:
// bit 0: self-powered
// bit 1: remote wakeup
pbData[0] = 0; // TODO use bmAttributes according to configuration
pbData[1] = 0;
*piLen = 2;
break;
case REQ_SET_ADDRESS:
USBHwSetAddress(pSetup->wValue);
break;
case REQ_GET_DESCRIPTOR:
DBG("D%x", pSetup->wValue);
return USBGetDescriptor(pSetup->wValue, pSetup->wIndex, piLen, ppbData);
case REQ_GET_CONFIGURATION:
// indicate if we are configured
pbData[0] = bConfiguration;
*piLen = 1;
break;
case REQ_SET_CONFIGURATION:
if (!USBSetConfiguration(pSetup->wValue & 0xFF, 0)) {
DBG("USBSetConfiguration failed!\n");
return FALSE;
}
// configuration successful, update current configuration
bConfiguration = pSetup->wValue & 0xFF;
break;
case REQ_CLEAR_FEATURE:
case REQ_SET_FEATURE:
if (pSetup->wValue == FEA_REMOTE_WAKEUP) {
// put DEVICE_REMOTE_WAKEUP code here
}
if (pSetup->wValue == FEA_TEST_MODE) {
// put TEST_MODE code here
}
return FALSE;
case REQ_SET_DESCRIPTOR:
DBG("Device req %d not implemented\n", pSetup->bRequest);
return FALSE;
default:
DBG("Illegal device req %d\n", pSetup->bRequest);
return FALSE;
}
return TRUE;
}
/**
Local function to handle a standard interface request
@param [in] pSetup The setup packet
@param [in,out] *piLen Pointer to data length
@param [in] ppbData Data buffer.
@return TRUE if the request was handled successfully
*/
static BOOL HandleStdInterfaceReq(TSetupPacket *pSetup, int *piLen, U8 **ppbData)
{
U8 *pbData = *ppbData;
switch (pSetup->bRequest) {
case REQ_GET_STATUS:
// no bits specified
pbData[0] = 0;
pbData[1] = 0;
*piLen = 2;
break;
case REQ_CLEAR_FEATURE:
case REQ_SET_FEATURE:
// not defined for interface
return FALSE;
case REQ_GET_INTERFACE: // TODO use bNumInterfaces
// there is only one interface, return n-1 (= 0)
pbData[0] = 0;
*piLen = 1;
break;
case REQ_SET_INTERFACE: // TODO use bNumInterfaces
// there is only one interface (= 0)
if (pSetup->wValue != 0) {
return FALSE;
}
*piLen = 0;
break;
default:
DBG("Illegal interface req %d\n", pSetup->bRequest);
return FALSE;
}
return TRUE;
}
/**
Local function to handle a standard endpoint request
@param [in] pSetup The setup packet
@param [in,out] *piLen Pointer to data length
@param [in] ppbData Data buffer.
@return TRUE if the request was handled successfully
*/
static BOOL HandleStdEndPointReq(TSetupPacket *pSetup, int *piLen, U8 **ppbData)
{
U8 *pbData = *ppbData;
switch (pSetup->bRequest) {
case REQ_GET_STATUS:
// bit 0 = endpointed halted or not
pbData[0] = USBHwEPIsStalled(pSetup->wIndex) ? 1 : 0;
pbData[1] = 0;
*piLen = 2;
break;
case REQ_CLEAR_FEATURE:
if (pSetup->wValue == FEA_ENDPOINT_HALT) {
// clear HALT by unstalling
USBHwEPStall(pSetup->wIndex, FALSE);
break;
}
// only ENDPOINT_HALT defined for endpoints
return FALSE;
case REQ_SET_FEATURE:
if (pSetup->wValue == FEA_ENDPOINT_HALT) {
// set HALT by stalling
USBHwEPStall(pSetup->wIndex, TRUE);
break;
}
// only ENDPOINT_HALT defined for endpoints
return FALSE;
case REQ_SYNCH_FRAME:
DBG("EP req %d not implemented\n", pSetup->bRequest);
return FALSE;
default:
DBG("Illegal EP req %d\n", pSetup->bRequest);
return FALSE;
}
return TRUE;
}
/**
Default handler for standard ('chapter 9') requests
If a custom request handler was installed, this handler is called first.
@param [in] pSetup The setup packet
@param [in,out] *piLen Pointer to data length
@param [in] ppbData Data buffer.
@return TRUE if the request was handled successfully
*/
BOOL USBHandleStandardRequest(TSetupPacket *pSetup, int *piLen, U8 **ppbData)
{
// try the custom request handler first
if ((pfnHandleCustomReq != NULL) && pfnHandleCustomReq(pSetup, piLen, ppbData)) {
return TRUE;
}
switch (REQTYPE_GET_RECIP(pSetup->bmRequestType)) {
case REQTYPE_RECIP_DEVICE: return HandleStdDeviceReq(pSetup, piLen, ppbData);
case REQTYPE_RECIP_INTERFACE: return HandleStdInterfaceReq(pSetup, piLen, ppbData);
case REQTYPE_RECIP_ENDPOINT: return HandleStdEndPointReq(pSetup, piLen, ppbData);
default: return FALSE;
}
}
/**
Registers a callback for custom device requests
In USBHandleStandardRequest, the custom request handler gets a first
chance at handling the request before it is handed over to the 'chapter 9'
request handler.
This can be used for example in HID devices, where a REQ_GET_DESCRIPTOR
request is sent to an interface, which is not covered by the 'chapter 9'
specification.
@param [in] pfnHandler Callback function pointer
*/
void USBRegisterCustomReqHandler(TFnHandleRequest *pfnHandler)
{
pfnHandleCustomReq = pfnHandler;
}

View File

@ -0,0 +1,94 @@
/**
(c) 2006, Bertrik Sikken, bertrik@sikken.nl
definitions of structure of standard USB packets
*/
#ifndef _USBSTRUCT_H_
#define _USBSTRUCT_H_
#include "type.h"
/** setup packet definitions */
typedef struct {
U8 bmRequestType; /**< characteristics of the specific request */
U8 bRequest; /**< specific request */
U16 wValue; /**< request specific parameter */
U16 wIndex; /**< request specific parameter */
U16 wLength; /**< length of data transfered in data phase */
} TSetupPacket;
#define REQTYPE_GET_DIR(x) (((x)>>7)&0x01)
#define REQTYPE_GET_TYPE(x) (((x)>>5)&0x03)
#define REQTYPE_GET_RECIP(x) ((x)&0x1F)
#define REQTYPE_DIR_TO_DEVICE 0
#define REQTYPE_DIR_TO_HOST 1
#define REQTYPE_TYPE_STANDARD 0
#define REQTYPE_TYPE_CLASS 1
#define REQTYPE_TYPE_VENDOR 2
#define REQTYPE_TYPE_RESERVED 3
#define REQTYPE_RECIP_DEVICE 0
#define REQTYPE_RECIP_INTERFACE 1
#define REQTYPE_RECIP_ENDPOINT 2
#define REQTYPE_RECIP_OTHER 3
/* standard requests */
#define REQ_GET_STATUS 0x00
#define REQ_CLEAR_FEATURE 0x01
#define REQ_SET_FEATURE 0x03
#define REQ_SET_ADDRESS 0x05
#define REQ_GET_DESCRIPTOR 0x06
#define REQ_SET_DESCRIPTOR 0x07
#define REQ_GET_CONFIGURATION 0x08
#define REQ_SET_CONFIGURATION 0x09
#define REQ_GET_INTERFACE 0x0A
#define REQ_SET_INTERFACE 0x0B
#define REQ_SYNCH_FRAME 0x0C
/* class requests HID */
#define HID_GET_REPORT 0x01
#define HID_GET_IDLE 0x02
#define HID_GET_PROTOCOL 0x03
#define HID_SET_REPORT 0x09
#define HID_SET_IDLE 0x0A
#define HID_SET_PROTOCOL 0x0B
/* feature selectors */
#define FEA_ENDPOINT_HALT 0x00
#define FEA_REMOTE_WAKEUP 0x01
#define FEA_TEST_MODE 0x02
/*
USB descriptors
*/
/** USB descriptor header */
typedef struct {
U8 bLength; /**< descriptor length */
U8 bDescriptorType; /**< descriptor type */
} TUSBDescHeader;
#define DESC_DEVICE 1
#define DESC_CONFIGURATION 2
#define DESC_STRING 3
#define DESC_INTERFACE 4
#define DESC_ENDPOINT 5
#define DESC_DEVICE_QUALIFIER 6
#define DESC_OTHER_SPEED 7
#define DESC_INTERFACE_POWER 8
#define DESC_HID_HID 0x21
#define DESC_HID_REPORT 0x22
#define DESC_HID_PHYSICAL 0x23
#define GET_DESC_TYPE(x) (((x)>>8)&0xFF)
#define GET_DESC_INDEX(x) ((x)&0xFF)
#endif /* _USBSTRUCT_H_ */