o add usb test
This commit is contained in:
parent
4fad7cab6d
commit
920913d9e1
@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
/*#define HW_ENDPOINT_LINUX*/
|
||||
/*#define HW_ENDPOINT_ATMEGA128_SD*/
|
||||
/*#define HW_ENDPOINT_ATMEGA128_SD*/
|
||||
|
||||
|
||||
#define HW_ENDPOINT_LPC2000_SD
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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();
|
||||
|
||||
19
poc/lpc2148_usb/client/Makefile
Normal file
19
poc/lpc2148_usb/client/Makefile
Normal 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
|
||||
|
||||
|
||||
193
poc/lpc2148_usb/client/main.c
Normal file
193
poc/lpc2148_usb/client/main.c
Normal 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;
|
||||
}
|
||||
|
||||
52
poc/lpc2148_usb/target/Makefile
Normal file
52
poc/lpc2148_usb/target/Makefile
Normal 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
|
||||
55
poc/lpc2148_usb/target/custom/Makefile
Normal file
55
poc/lpc2148_usb/target/custom/Makefile
Normal 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
|
||||
|
||||
65
poc/lpc2148_usb/target/custom/console.c
Normal file
65
poc/lpc2148_usb/target/custom/console.c
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
5
poc/lpc2148_usb/target/custom/console.h
Normal file
5
poc/lpc2148_usb/target/custom/console.h
Normal file
@ -0,0 +1,5 @@
|
||||
void ConsoleInit(int iDivider);
|
||||
int putchar(int c);
|
||||
int puts(char *s);
|
||||
|
||||
|
||||
110
poc/lpc2148_usb/target/custom/crt.s
Normal file
110
poc/lpc2148_usb/target/custom/crt.s
Normal 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
|
||||
7
poc/lpc2148_usb/target/custom/flash.ocd
Normal file
7
poc/lpc2148_usb/target/custom/flash.ocd
Normal 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
|
||||
197
poc/lpc2148_usb/target/custom/lpc2148-ram.ld
Normal file
197
poc/lpc2148_usb/target/custom/lpc2148-ram.ld
Normal 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 */
|
||||
|
||||
197
poc/lpc2148_usb/target/custom/lpc2148-rom.ld
Normal file
197
poc/lpc2148_usb/target/custom/lpc2148-rom.ld
Normal 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 */
|
||||
|
||||
265
poc/lpc2148_usb/target/custom/main_custom.c
Normal file
265
poc/lpc2148_usb/target/custom/main_custom.c
Normal 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;
|
||||
}
|
||||
|
||||
268
poc/lpc2148_usb/target/custom/printf.c
Normal file
268
poc/lpc2148_usb/target/custom/printf.c
Normal 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
|
||||
126
poc/lpc2148_usb/target/custom/startup.c
Normal file
126
poc/lpc2148_usb/target/custom/startup.c
Normal 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;
|
||||
}
|
||||
|
||||
2
poc/lpc2148_usb/target/custom/startup.h
Normal file
2
poc/lpc2148_usb/target/custom/startup.h
Normal file
@ -0,0 +1,2 @@
|
||||
void Initialize(void);
|
||||
|
||||
31
poc/lpc2148_usb/target/lpcusb.tmproj
Normal file
31
poc/lpc2148_usb/target/lpcusb.tmproj
Normal 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>
|
||||
31
poc/lpc2148_usb/target/type.h
Normal file
31
poc/lpc2148_usb/target/type.h
Normal 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_ */
|
||||
|
||||
95
poc/lpc2148_usb/target/usbapi.h
Normal file
95
poc/lpc2148_usb/target/usbapi.h
Normal 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);
|
||||
222
poc/lpc2148_usb/target/usbcontrol.c
Normal file
222
poc/lpc2148_usb/target/usbcontrol.c
Normal 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;
|
||||
}
|
||||
|
||||
12
poc/lpc2148_usb/target/usbdebug.h
Normal file
12
poc/lpc2148_usb/target/usbdebug.h
Normal 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
|
||||
|
||||
541
poc/lpc2148_usb/target/usbhw_lpc.c
Normal file
541
poc/lpc2148_usb/target/usbhw_lpc.c
Normal 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;
|
||||
}
|
||||
|
||||
156
poc/lpc2148_usb/target/usbhw_lpc.h
Normal file
156
poc/lpc2148_usb/target/usbhw_lpc.h
Normal 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)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
69
poc/lpc2148_usb/target/usbinit.c
Normal file
69
poc/lpc2148_usb/target/usbinit.c
Normal 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;
|
||||
}
|
||||
|
||||
415
poc/lpc2148_usb/target/usbstdreq.c
Normal file
415
poc/lpc2148_usb/target/usbstdreq.c
Normal 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;
|
||||
}
|
||||
|
||||
94
poc/lpc2148_usb/target/usbstruct.h
Normal file
94
poc/lpc2148_usb/target/usbstruct.h
Normal 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_ */
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user