From ac089d4fb930b7dbc4161259fd9bddba94395ebc Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 17 May 2013 03:36:47 -0700 Subject: [PATCH] altos/lpc: Get USB working The lpc demo now has a USB command line. Also allocates system stack so we know when ram is tight at build time Signed-off-by: Keith Packard --- src/lpc/Makefile.defs | 2 +- src/lpc/altos.ld | 5 +- src/lpc/ao_arch.h | 8 +- src/lpc/ao_arch_funcs.h | 2 +- src/lpc/ao_timer_lpc.c | 33 +- src/lpc/ao_usb_lpc.c | 811 +++++++++++++++++---------------------- src/lpc/lpc.h | 89 +++-- src/lpc/registers.ld | 2 + src/lpcxpresso/Makefile | 2 + src/lpcxpresso/ao_demo.c | 26 +- src/lpcxpresso/ao_pins.h | 5 +- 11 files changed, 446 insertions(+), 539 deletions(-) diff --git a/src/lpc/Makefile.defs b/src/lpc/Makefile.defs index c18284d2..b63bdd12 100644 --- a/src/lpc/Makefile.defs +++ b/src/lpc/Makefile.defs @@ -7,7 +7,7 @@ vpath load_csv.5c ../kalman vpath matrix.5c ../kalman vpath ao-make-product.5c ../util -CC=arm-none-eabi-gcc +CC=/usr/bin/arm-none-eabi-gcc SAT=/opt/cortex SAT_CLIB=$(SAT)/lib/pdclib-cortex-m0.a SAT_CFLAGS=-I$(SAT)/include diff --git a/src/lpc/altos.ld b/src/lpc/altos.ld index 7a99e66b..bcfba1ea 100644 --- a/src/lpc/altos.ld +++ b/src/lpc/altos.ld @@ -17,7 +17,8 @@ MEMORY { rom (rx) : ORIGIN = 0x00000000, LENGTH = 32K - ram (!w) : ORIGIN = 0x10000000, LENGTH = 4K + ram (!w) : ORIGIN = 0x10000000, LENGTH = 4K - 512 + stack (!w) : ORIGIN = 0x10000000 + 4K - 512, LENGTH = 512 } INCLUDE registers.ld @@ -63,7 +64,7 @@ SECTIONS { __bss_end__ = .; } >ram - PROVIDE(__stack__ = ORIGIN(ram) + LENGTH(ram)); + PROVIDE(__stack__ = ORIGIN(stack) + LENGTH(stack)); PROVIDE(end = .); } diff --git a/src/lpc/ao_arch.h b/src/lpc/ao_arch.h index 61182160..99c646f9 100644 --- a/src/lpc/ao_arch.h +++ b/src/lpc/ao_arch.h @@ -45,7 +45,10 @@ #define __interrupt(n) #define __at(n) -#define ao_arch_reboot() +#define ao_arch_reboot() arm_scb.aircr = ((0x05fa << 16) | \ + (0 << 15) | \ + (1 << 2) | \ + (0 << 1)) #define ao_arch_nop() asm("nop") @@ -114,7 +117,8 @@ extern const uint32_t ao_radio_cal; void ao_adc_init(void); - +#define AO_USB_OUT_EP 2 +#define AO_USB_IN_EP 3 void ao_serial_init(void); diff --git a/src/lpc/ao_arch_funcs.h b/src/lpc/ao_arch_funcs.h index 39222b9d..96ae0366 100644 --- a/src/lpc/ao_arch_funcs.h +++ b/src/lpc/ao_arch_funcs.h @@ -124,7 +124,7 @@ static inline void ao_arch_restore_stack(void) { /* Restore APSR */ asm("pop {r0}"); - asm("msr apsr,r0"); + asm("msr apsr_nczvq,r0"); /* Restore general registers and return */ asm("pop {r0-r7,pc}\n"); diff --git a/src/lpc/ao_timer_lpc.c b/src/lpc/ao_timer_lpc.c index 51e82525..51835baa 100644 --- a/src/lpc/ao_timer_lpc.c +++ b/src/lpc/ao_timer_lpc.c @@ -78,6 +78,14 @@ ao_timer_init(void) #define AO_LPC_FCCO_MIN 156000000 +static void +ao_clock_delay(void) +{ + uint32_t i; + for (i = 0; i < 200; i++) + ao_arch_nop(); +} + void ao_clock_init(void) { @@ -94,11 +102,15 @@ ao_clock_init(void) /* Turn the IRC clock back on */ lpc_scb.pdruncfg &= ~(1 << LPC_SCB_PDRUNCFG_IRC_PD); + ao_clock_delay(); /* Switch to the IRC clock */ lpc_scb.mainclksel = LPC_SCB_MAINCLKSEL_SEL_IRC << LPC_SCB_MAINCLKSEL_SEL; + lpc_scb.mainclkuen = (1 << LPC_SCB_MAINCLKUEN_ENA); lpc_scb.mainclkuen = (0 << LPC_SCB_MAINCLKUEN_ENA); lpc_scb.mainclkuen = (1 << LPC_SCB_MAINCLKUEN_ENA); + while (!(lpc_scb.mainclkuen & (1 << LPC_SCB_MAINCLKUEN_ENA))) + ; /* Find a PLL post divider ratio that gets the FCCO in range */ for (p = 0; p < 4; p++) @@ -110,14 +122,15 @@ ao_clock_init(void) /* Power down the PLL before touching the registers */ lpc_scb.pdruncfg |= (1 << LPC_SCB_PDRUNCFG_SYSPLL_PD); + ao_clock_delay(); /* Set PLL divider values */ lpc_scb.syspllctrl = ((AO_LPC_M << LPC_SCB_SYSPLLCTRL_MSEL) | (p << LPC_SCB_SYSPLLCTRL_PSEL)); - /* Turn off the external crystal clock */ lpc_scb.pdruncfg |= (1 << LPC_SCB_PDRUNCFG_SYSOSC_PD); + ao_clock_delay(); /* Configure the crystal clock */ lpc_scb.sysoscctrl = ((0 << LPC_SCB_SYSOSCCTRL_BYPASS) | /* using a crystal */ @@ -125,12 +138,16 @@ ao_clock_init(void) /* Turn on the external crystal clock */ lpc_scb.pdruncfg &= ~(1 << LPC_SCB_PDRUNCFG_SYSOSC_PD); + ao_clock_delay(); /* Select crystal as PLL input */ lpc_scb.syspllclksel = (LPC_SCB_SYSPLLCLKSEL_SEL_SYSOSC << LPC_SCB_SYSPLLCLKSEL_SEL); - lpc_scb.syspllclkuen = 0; lpc_scb.syspllclkuen = (1 << LPC_SCB_SYSPLLCLKUEN_ENA); + lpc_scb.syspllclkuen = (0 << LPC_SCB_SYSPLLCLKUEN_ENA); + lpc_scb.syspllclkuen = (1 << LPC_SCB_SYSPLLCLKUEN_ENA); + while (!(lpc_scb.syspllclkuen & (1 << LPC_SCB_SYSPLLCLKUEN_ENA))) + ; /* Turn on the PLL */ lpc_scb.pdruncfg &= ~(1 << LPC_SCB_PDRUNCFG_SYSPLL_PD); @@ -145,17 +162,15 @@ ao_clock_init(void) /* Switch to the PLL */ lpc_scb.mainclksel = LPC_SCB_MAINCLKSEL_SEL_PLL_OUTPUT << LPC_SCB_MAINCLKSEL_SEL; - lpc_scb.mainclkuen = 0 << LPC_SCB_MAINCLKUEN_ENA; - lpc_scb.mainclkuen = 1 << LPC_SCB_MAINCLKUEN_ENA; + lpc_scb.mainclkuen = (1 << LPC_SCB_MAINCLKUEN_ENA); + lpc_scb.mainclkuen = (0 << LPC_SCB_MAINCLKUEN_ENA); + lpc_scb.mainclkuen = (1 << LPC_SCB_MAINCLKUEN_ENA); + while (!(lpc_scb.mainclkuen & (1 << LPC_SCB_MAINCLKUEN_ENA))) + ; /* Set system clock divider */ lpc_scb.sysahbclkdiv = AO_LPC_CLKOUT / AO_LPC_SYSCLK; - /* Set USB clock source */ - lpc_scb.usbclksel = (LPC_SCB_USBCLKSEL_SEL_MAIN_CLOCK << LPC_SCB_USBCLKSEL_SEL); - lpc_scb.usbclkuen = (0 << LPC_SCB_USBCLKUEN_ENA); - lpc_scb.usbclkuen = (1 << LPC_SCB_USBCLKUEN_ENA); - /* Shut down perhipheral clocks (enabled as needed) */ lpc_scb.ssp0clkdiv = 0; lpc_scb.uartclkdiv = 0; diff --git a/src/lpc/ao_usb_lpc.c b/src/lpc/ao_usb_lpc.c index af2bd271..0f881720 100644 --- a/src/lpc/ao_usb_lpc.c +++ b/src/lpc/ao_usb_lpc.c @@ -19,9 +19,9 @@ #include "ao_usb.h" #include "ao_product.h" -#define USB_DEBUG 1 -#define USB_DEBUG_DATA 1 -#define USB_ECHO 1 +#define USB_DEBUG 0 +#define USB_DEBUG_DATA 0 +#define USB_ECHO 0 #if USB_DEBUG #define debug(format, args...) printf(format, ## args); @@ -62,35 +62,26 @@ static uint8_t ao_usb_ep0_out_len; * Objects allocated in special USB memory */ -/* Buffer description tables */ -static union lpc_usb_bdt *ao_usb_bdt; /* USB address of end of allocated storage */ -static uint16_t ao_usb_sram_addr; +static uint8_t *ao_usb_sram; /* Pointer to ep0 tx/rx buffers in USB memory */ -static uint32_t *ao_usb_ep0_tx_buffer; -static uint32_t *ao_usb_ep0_rx_buffer; +static uint8_t *ao_usb_ep0_tx_buffer; +static uint8_t *ao_usb_ep0_setup_buffer; +static uint8_t *ao_usb_ep0_rx_buffer; /* Pointer to bulk data tx/rx buffers in USB memory */ -static uint32_t *ao_usb_in_tx_buffer; -static uint32_t *ao_usb_out_rx_buffer; +static uint8_t *ao_usb_in_tx_buffer; +static uint8_t *ao_usb_out_rx_buffer; -/* System ram shadow of USB buffer; writing individual bytes is - * too much of a pain (sigh) */ +/* Our data buffers */ static uint8_t ao_usb_tx_buffer[AO_USB_IN_SIZE]; static uint8_t ao_usb_tx_count; static uint8_t ao_usb_rx_buffer[AO_USB_OUT_SIZE]; static uint8_t ao_usb_rx_count, ao_usb_rx_pos; -/* - * End point register indices - */ - -#define AO_USB_CONTROL_EPR 0 -#define AO_USB_INT_EPR 1 -#define AO_USB_OUT_EPR 2 -#define AO_USB_IN_EPR 3 +static struct lpc_usb_endpoint lpc_usb_endpoint __attribute((aligned(256))); /* Marks when we don't need to send an IN packet. * This happens only when the last IN packet is not full, @@ -129,39 +120,6 @@ static inline uint32_t set_toggle(uint32_t current_value, return (current_value ^ desired_value) & mask; } -static inline uint32_t *ao_usb_packet_buffer_addr(uint16_t sram_addr) -{ - return (uint32_t *) (lpc_usb_sram + 2 * sram_addr); -} - -static inline uint32_t ao_usb_epr_stat_rx(uint32_t epr) { - return (epr >> USB_USB_EPR_STAT_RX) & USB_USB_EPR_STAT_RX_MASK; -} - -static inline uint32_t ao_usb_epr_stat_tx(uint32_t epr) { - return (epr >> USB_USB_EPR_STAT_TX) & USB_USB_EPR_STAT_TX_MASK; -} - -static inline uint32_t ao_usb_epr_ctr_rx(uint32_t epr) { - return (epr >> USB_USB_EPR_CTR_RX) & 1; -} - -static inline uint32_t ao_usb_epr_ctr_tx(uint32_t epr) { - return (epr >> USB_USB_EPR_CTR_TX) & 1; -} - -static inline uint32_t ao_usb_epr_setup(uint32_t epr) { - return (epr >> USB_USB_EPR_SETUP) & 1; -} - -static inline uint32_t ao_usb_epr_dtog_rx(uint32_t epr) { - return (epr >> USB_USB_EPR_DTOG_RX) & 1; -} - -static inline uint32_t ao_usb_epr_dtog_tx(uint32_t epr) { - return (epr >> USB_USB_EPR_DTOG_TX) & 1; -} - /* * Set current device address and mark the * interface as active @@ -170,36 +128,24 @@ void ao_usb_set_address(uint8_t address) { debug("ao_usb_set_address %02x\n", address); - lpc_usb.daddr = (1 << USB_USB_DADDR_EF) | address; + lpc_usb.devcmdstat = ((address << LPC_USB_DEVCMDSTAT_DEV_ADDR) | + (1 << LPC_USB_DEVCMDSTAT_DEV_EN) | + (0 << LPC_USB_DEVCMDSTAT_SETUP) | + (0 << LPC_USB_DEVCMDSTAT_PLL_ON) | + (0 << LPC_USB_DEVCMDSTAT_LPM_SUP) | + (0 << LPC_USB_DEVCMDSTAT_INTONNAK_AO) | + (0 << LPC_USB_DEVCMDSTAT_INTONNAK_AI) | + (0 << LPC_USB_DEVCMDSTAT_INTONNAK_CO) | + (0 << LPC_USB_DEVCMDSTAT_INTONNAK_CI) | + (1 << LPC_USB_DEVCMDSTAT_DCON) | + (0 << LPC_USB_DEVCMDSTAT_DSUS) | + (0 << LPC_USB_DEVCMDSTAT_DCON_C) | + (0 << LPC_USB_DEVCMDSTAT_DSUS_C) | + (0 << LPC_USB_DEVCMDSTAT_DRES_C) | + (0 << LPC_USB_DEVCMDSTAT_VBUSDEBOUNCED)); ao_usb_address_pending = 0; } -/* - * Write these values to preserve register contents under HW changes - */ - -#define USB_USB_EPR_INVARIANT ((1 << USB_USB_EPR_CTR_RX) | \ - (USB_USB_EPR_DTOG_RX_WRITE_INVARIANT << USB_USB_EPR_DTOG_RX) | \ - (USB_USB_EPR_STAT_RX_WRITE_INVARIANT << USB_USB_EPR_STAT_RX) | \ - (1 << USB_USB_EPR_CTR_TX) | \ - (USB_USB_EPR_DTOG_TX_WRITE_INVARIANT << USB_USB_EPR_DTOG_TX) | \ - (USB_USB_EPR_STAT_TX_WRITE_INVARIANT << USB_USB_EPR_STAT_TX)) - -#define USB_USB_EPR_INVARIANT_MASK ((1 << USB_USB_EPR_CTR_RX) | \ - (USB_USB_EPR_DTOG_RX_MASK << USB_USB_EPR_DTOG_RX) | \ - (USB_USB_EPR_STAT_RX_MASK << USB_USB_EPR_STAT_RX) | \ - (1 << USB_USB_EPR_CTR_TX) | \ - (USB_USB_EPR_DTOG_TX_MASK << USB_USB_EPR_DTOG_TX) | \ - (USB_USB_EPR_STAT_TX_MASK << USB_USB_EPR_STAT_TX)) - -/* - * These bits are purely under sw control, so preserve them in the - * register by re-writing what was read - */ -#define USB_USB_EPR_PRESERVE_MASK ((USB_USB_EPR_EP_TYPE_MASK << USB_USB_EPR_EP_TYPE) | \ - (1 << USB_USB_EPR_EP_KIND) | \ - (USB_USB_EPR_EA_MASK << USB_USB_EPR_EA)) - #define TX_DBG 0 #define RX_DBG 0 @@ -224,338 +170,192 @@ static void _dbg(int line, char *msg, uint32_t value); #endif /* - * Set the state of the specified endpoint register to a new - * value. This is tricky because the bits toggle where the new - * value is one, and we need to write invariant values in other - * spots of the register. This hardware is strange... + * Set just endpoint 0, for use during startup */ -static void -_ao_usb_set_stat_tx(int ep, uint32_t stat_tx) + +static uint8_t * +ao_usb_alloc_sram(uint16_t size) { - uint32_t epr_write, epr_old; - - _tx_dbg1("set_stat_tx top", stat_tx); - epr_old = epr_write = lpc_usb.epr[ep]; - epr_write &= USB_USB_EPR_PRESERVE_MASK; - epr_write |= USB_USB_EPR_INVARIANT; - epr_write |= set_toggle(epr_old, - USB_USB_EPR_STAT_TX_MASK << USB_USB_EPR_STAT_TX, - stat_tx << USB_USB_EPR_STAT_TX); - lpc_usb.epr[ep] = epr_write; - _tx_dbg1("set_stat_tx bottom", epr_write); + uint8_t *addr = ao_usb_sram; + + ao_usb_sram += (size + 63) & ~63; + return addr; } -static void -ao_usb_set_stat_tx(int ep, uint32_t stat_tx) +static uint16_t +ao_usb_sram_offset(uint8_t *addr) { - ao_arch_block_interrupts(); - _ao_usb_set_stat_tx(ep, stat_tx); - ao_arch_release_interrupts(); + return (uint16_t) ((intptr_t) addr >> 6); } static void -_ao_usb_set_stat_rx(int ep, uint32_t stat_rx) { - uint32_t epr_write, epr_old; - - epr_write = epr_old = lpc_usb.epr[ep]; - epr_write &= USB_USB_EPR_PRESERVE_MASK; - epr_write |= USB_USB_EPR_INVARIANT; - epr_write |= set_toggle(epr_old, - USB_USB_EPR_STAT_RX_MASK << USB_USB_EPR_STAT_RX, - stat_rx << USB_USB_EPR_STAT_RX); - lpc_usb.epr[ep] = epr_write; +ao_usb_set_ep(vuint32_t *ep, uint8_t *addr, uint16_t nbytes) +{ + *ep = ((ao_usb_sram_offset(addr) << LPC_USB_EP_OFFSET) | + (nbytes << LPC_USB_EP_NBYTES) | + (0 << LPC_USB_EP_ENDPOINT_ISO) | + (0 << LPC_USB_EP_RATE_FEEDBACK) | + (0 << LPC_USB_EP_TOGGLE_RESET) | + (0 << LPC_USB_EP_STALL) | + (0 << LPC_USB_EP_DISABLED) | + (1 << LPC_USB_EP_ACTIVE)); } -static void -ao_usb_set_stat_rx(int ep, uint32_t stat_rx) { - ao_arch_block_interrupts(); - _ao_usb_set_stat_rx(ep, stat_rx); - ao_arch_release_interrupts(); +static inline uint16_t +ao_usb_ep_count(vuint32_t *ep) +{ + return (*ep >> LPC_USB_EP_NBYTES) & LPC_USB_EP_NBYTES_MASK; } -/* - * Set just endpoint 0, for use during startup - */ - -static void -ao_usb_init_ep(uint8_t ep, uint32_t addr, uint32_t type, uint32_t stat_rx, uint32_t stat_tx) +static inline uint8_t +ao_usb_ep_stall(vuint32_t *ep) { - uint32_t epr; - ao_arch_block_interrupts(); - epr = lpc_usb.epr[ep]; - epr = ((0 << USB_USB_EPR_CTR_RX) | - (epr & (1 << USB_USB_EPR_DTOG_RX)) | - set_toggle(epr, - (USB_USB_EPR_STAT_RX_MASK << USB_USB_EPR_STAT_RX), - (stat_rx << USB_USB_EPR_STAT_RX)) | - (type << USB_USB_EPR_EP_TYPE) | - (0 << USB_USB_EPR_EP_KIND) | - (0 << USB_USB_EPR_CTR_TX) | - (epr & (1 << USB_USB_EPR_DTOG_TX)) | - set_toggle(epr, - (USB_USB_EPR_STAT_TX_MASK << USB_USB_EPR_STAT_TX), - (stat_tx << USB_USB_EPR_STAT_TX)) | - (addr << USB_USB_EPR_EA)); - lpc_usb.epr[ep] = epr; - ao_arch_release_interrupts(); - debug ("writing epr[%d] 0x%08x wrote 0x%08x\n", - ep, epr, lpc_usb.epr[ep]); + return (*ep >> LPC_USB_EP_STALL) & 1; } -static void -ao_usb_set_ep0(void) +static inline vuint32_t * +ao_usb_ep0_out(void) { - uint32_t epr; - int e; - - ao_usb_sram_addr = 0; - - /* buffer table is at the start of USB memory */ - lpc_usb.btable = 0; - ao_usb_bdt = (void *) lpc_usb_sram; - - ao_usb_sram_addr += 8 * USB_USB_BDT_SIZE; - - /* Set up EP 0 - a Control end point with 32 bytes of in and out buffers */ - - ao_usb_bdt[0].single.addr_tx = ao_usb_sram_addr; - ao_usb_bdt[0].single.count_tx = 0; - ao_usb_ep0_tx_buffer = ao_usb_packet_buffer_addr(ao_usb_sram_addr); - ao_usb_sram_addr += AO_USB_CONTROL_SIZE; - - ao_usb_bdt[0].single.addr_rx = ao_usb_sram_addr; - ao_usb_bdt[0].single.count_rx = ((1 << USB_USB_BDT_COUNT_RX_BL_SIZE) | - (((AO_USB_CONTROL_SIZE / 32) - 1) << USB_USB_BDT_COUNT_RX_NUM_BLOCK)); - ao_usb_ep0_rx_buffer = ao_usb_packet_buffer_addr(ao_usb_sram_addr); - ao_usb_sram_addr += AO_USB_CONTROL_SIZE; + return &lpc_usb_endpoint.ep0_out; +} - ao_usb_init_ep(AO_USB_CONTROL_EPR, AO_USB_CONTROL_EP, - USB_USB_EPR_EP_TYPE_CONTROL, - USB_USB_EPR_STAT_RX_VALID, - USB_USB_EPR_STAT_TX_NAK); +static inline vuint32_t * +ao_usb_ep0_in(void) +{ + return &lpc_usb_endpoint.ep0_in; +} - /* Clear all of the other endpoints */ - for (e = 1; e < 8; e++) { - ao_usb_init_ep(e, 0, - USB_USB_EPR_EP_TYPE_CONTROL, - USB_USB_EPR_STAT_RX_DISABLED, - USB_USB_EPR_STAT_TX_DISABLED); - } +static inline vuint32_t * +ao_usb_epn_out(uint8_t n) +{ + return &lpc_usb_endpoint.epn[n-1].out[0]; +} - ao_usb_set_address(0); +static inline vuint32_t * +ao_usb_epn_in(uint8_t n) +{ + return &lpc_usb_endpoint.epn[n-1].in[0]; } static void -ao_usb_set_configuration(void) +ao_usb_set_epn_in(uint8_t n, uint8_t *addr, uint16_t nbytes) { - uint32_t epr; - - debug ("ao_usb_set_configuration\n"); - - /* Set up the INT end point */ - ao_usb_bdt[AO_USB_INT_EPR].single.addr_tx = ao_usb_sram_addr; - ao_usb_bdt[AO_USB_INT_EPR].single.count_tx = 0; - ao_usb_in_tx_buffer = ao_usb_packet_buffer_addr(ao_usb_sram_addr); - ao_usb_sram_addr += AO_USB_INT_SIZE; - - ao_usb_init_ep(AO_USB_INT_EPR, - AO_USB_INT_EP, - USB_USB_EPR_EP_TYPE_INTERRUPT, - USB_USB_EPR_STAT_RX_DISABLED, - USB_USB_EPR_STAT_TX_NAK); - - /* Set up the OUT end point */ - ao_usb_bdt[AO_USB_OUT_EPR].single.addr_rx = ao_usb_sram_addr; - ao_usb_bdt[AO_USB_OUT_EPR].single.count_rx = ((1 << USB_USB_BDT_COUNT_RX_BL_SIZE) | - (((AO_USB_OUT_SIZE / 32) - 1) << USB_USB_BDT_COUNT_RX_NUM_BLOCK)); - ao_usb_out_rx_buffer = ao_usb_packet_buffer_addr(ao_usb_sram_addr); - ao_usb_sram_addr += AO_USB_OUT_SIZE; - - ao_usb_init_ep(AO_USB_OUT_EPR, - AO_USB_OUT_EP, - USB_USB_EPR_EP_TYPE_BULK, - USB_USB_EPR_STAT_RX_VALID, - USB_USB_EPR_STAT_TX_DISABLED); - - /* Set up the IN end point */ - ao_usb_bdt[AO_USB_IN_EPR].single.addr_tx = ao_usb_sram_addr; - ao_usb_bdt[AO_USB_IN_EPR].single.count_tx = 0; - ao_usb_in_tx_buffer = ao_usb_packet_buffer_addr(ao_usb_sram_addr); - ao_usb_sram_addr += AO_USB_IN_SIZE; - - ao_usb_init_ep(AO_USB_IN_EPR, - AO_USB_IN_EP, - USB_USB_EPR_EP_TYPE_BULK, - USB_USB_EPR_STAT_RX_DISABLED, - USB_USB_EPR_STAT_TX_NAK); - - ao_usb_running = 1; + ao_usb_set_ep(ao_usb_epn_in(n), addr, nbytes); } -static uint16_t control_count; -static uint16_t int_count; -static uint16_t in_count; -static uint16_t out_count; -static uint16_t reset_count; - -void -lpc_usb_lp_isr(void) +static void +ao_usb_set_epn_out(uint8_t n, uint8_t *addr, uint16_t nbytes) { - uint32_t istr = lpc_usb.istr; - - if (istr & (1 << USB_USB_ISTR_CTR)) { - uint8_t ep = istr & USB_USB_ISTR_EP_ID_MASK; - uint32_t epr, epr_write; - - /* Preserve the SW write bits, don't mess with most HW writable bits, - * clear the CTR_RX and CTR_TX bits - */ - epr = lpc_usb.epr[ep]; - epr_write = epr; - epr_write &= USB_USB_EPR_PRESERVE_MASK; - epr_write |= USB_USB_EPR_INVARIANT; - epr_write &= ~(1 << USB_USB_EPR_CTR_RX); - epr_write &= ~(1 << USB_USB_EPR_CTR_TX); - lpc_usb.epr[ep] = epr_write; - - switch (ep) { - case 0: - ++control_count; - if (ao_usb_epr_ctr_rx(epr)) { - if (ao_usb_epr_setup(epr)) - ao_usb_ep0_receive |= AO_USB_EP0_GOT_SETUP; - else - ao_usb_ep0_receive |= AO_USB_EP0_GOT_RX_DATA; - } - if (ao_usb_epr_ctr_tx(epr)) - ao_usb_ep0_receive |= AO_USB_EP0_GOT_TX_ACK; - ao_wakeup(&ao_usb_ep0_receive); - break; - case AO_USB_OUT_EPR: - ++out_count; - if (ao_usb_epr_ctr_rx(epr)) { - _rx_dbg1("RX ISR", epr); - ao_usb_out_avail = 1; - _rx_dbg0("out avail set"); - ao_wakeup(&ao_stdin_ready); - _rx_dbg0("stdin awoken"); - } - break; - case AO_USB_IN_EPR: - ++in_count; - _tx_dbg1("TX ISR", epr); - if (ao_usb_epr_ctr_tx(epr)) { - ao_usb_in_pending = 0; - ao_wakeup(&ao_usb_in_pending); - } - break; - case AO_USB_INT_EPR: - ++int_count; - if (ao_usb_epr_ctr_tx(epr)) - _ao_usb_set_stat_tx(AO_USB_INT_EPR, USB_USB_EPR_STAT_TX_NAK); - break; - } - return; - } - - if (istr & (1 << USB_USB_ISTR_RESET)) { - ++reset_count; - lpc_usb.istr &= ~(1 << USB_USB_ISTR_RESET); - ao_usb_ep0_receive |= AO_USB_EP0_GOT_RESET; - ao_wakeup(&ao_usb_ep0_receive); - } + ao_usb_set_ep(ao_usb_epn_out(n), addr, nbytes); } -void -lpc_usb_fs_wkup(void) +static inline uint16_t +ao_usb_epn_out_count(uint8_t n) { - /* USB wakeup, just clear the bit for now */ - lpc_usb.istr &= ~(1 << USB_USB_ISTR_WKUP); + return ao_usb_ep_count(ao_usb_epn_out(n)); } -/* The USB memory holds 16 bit values on 32 bit boundaries - * and must be accessed only in 32 bit units. Sigh. - */ +static inline uint16_t +ao_usb_epn_in_count(uint8_t n) +{ + return ao_usb_ep_count(ao_usb_epn_in(n)); +} -static inline void -ao_usb_write_byte(uint8_t byte, uint32_t *base, uint16_t offset) +static uint8_t * +ao_usb_enable_ep(vuint32_t *ep, uint16_t nbytes, uint16_t set_nbytes) { - base += offset >> 1; - if (offset & 1) { - *base = (*base & 0xff) | ((uint32_t) byte << 8); - } else { - *base = (*base & 0xff00) | byte; - } + uint8_t *addr = ao_usb_alloc_sram(nbytes); + + ao_usb_set_ep(ep, addr, set_nbytes); + return addr; } -static inline void -ao_usb_write_short(uint16_t data, uint32_t *base, uint16_t offset) +static void +ao_usb_disable_ep(vuint32_t *ep) { - base[offset>>1] = data; + *ep = ((0 << LPC_USB_EP_OFFSET) | + (0 << LPC_USB_EP_NBYTES) | + (0 << LPC_USB_EP_ENDPOINT_ISO) | + (0 << LPC_USB_EP_RATE_FEEDBACK) | + (0 << LPC_USB_EP_TOGGLE_RESET) | + (0 << LPC_USB_EP_STALL) | + (1 << LPC_USB_EP_DISABLED) | + (0 << LPC_USB_EP_ACTIVE)); } static void -ao_usb_write(const uint8_t *src, uint32_t *base, uint16_t offset, uint16_t bytes) +ao_usb_enable_epn(uint8_t n, uint16_t out_bytes, uint8_t **out_addr, uint16_t in_bytes, uint8_t **in_addr) { - if (!bytes) - return; - if (offset & 1) { - debug_data (" %02x", src[0]); - ao_usb_write_byte(*src++, base, offset++); - bytes--; - } - while (bytes >= 2) { - debug_data (" %02x %02x", src[0], src[1]); - ao_usb_write_short((src[1] << 8) | src[0], base, offset); - offset += 2; - src += 2; - bytes -= 2; - } - if (bytes) { - debug_data (" %02x", src[0]); - ao_usb_write_byte(*src, base, offset); - } + uint8_t *addr; + + addr = ao_usb_enable_ep(ao_usb_epn_out(n), out_bytes, out_bytes); + if (out_addr) + *out_addr = addr; + ao_usb_disable_ep(&lpc_usb_endpoint.epn[n-1].out[1]); + + addr = ao_usb_enable_ep(ao_usb_epn_in(n), in_bytes, 0); + if (in_addr) + *in_addr = addr; + ao_usb_disable_ep(&lpc_usb_endpoint.epn[n-1].in[1]); } -static inline uint8_t -ao_usb_read_byte(uint32_t *base, uint16_t offset) +static void +ao_usb_disable_epn(uint8_t n) { - base += offset >> 1; - if (offset & 1) - return (*base >> 8) & 0xff; - else - return *base & 0xff; + ao_usb_disable_ep(ao_usb_epn_out(n)); + ao_usb_disable_ep(&lpc_usb_endpoint.epn[n-1].out[1]); + ao_usb_disable_ep(ao_usb_epn_in(n)); + ao_usb_disable_ep(&lpc_usb_endpoint.epn[n-1].in[1]); } -static inline uint16_t -ao_usb_read_short(uint32_t *base, uint16_t offset) +static void +ao_usb_set_ep0(void) { - return base[offset>>1]; + int e; + + /* Everything is single buffered for now */ + lpc_usb.epbufcfg = 0; + lpc_usb.epinuse = 0; + lpc_usb.epskip = 0xffffffff; + + ao_usb_set_address(0); + lpc_usb.intstat = 0xc00003ff; + + ao_usb_configuration = 0; + + ao_usb_sram = lpc_usb_sram; + + lpc_usb.epliststart = (uint32_t) (intptr_t) &lpc_usb_endpoint; + lpc_usb.databufstart = ((uint32_t) (intptr_t) ao_usb_sram) & 0xffc00000; + + /* Set up EP 0 - a Control end point with 32 bytes of in and out buffers */ + + ao_usb_ep0_rx_buffer = ao_usb_enable_ep(ao_usb_ep0_out(), AO_USB_CONTROL_SIZE, AO_USB_CONTROL_SIZE); + ao_usb_ep0_setup_buffer = ao_usb_alloc_sram(AO_USB_CONTROL_SIZE); + lpc_usb_endpoint.setup = ao_usb_sram_offset(ao_usb_ep0_setup_buffer); + ao_usb_ep0_tx_buffer = ao_usb_enable_ep(ao_usb_ep0_in(), AO_USB_CONTROL_SIZE, 0); + + /* Clear all of the other endpoints */ + for (e = 1; e <= 4; e++) + ao_usb_disable_epn(e); + } static void -ao_usb_read(uint8_t *dst, uint32_t *base, uint16_t offset, uint16_t bytes) +ao_usb_set_configuration(void) { - if (!bytes) - return; - if (offset & 1) { - *dst++ = ao_usb_read_byte(base, offset++); - debug_data (" %02x", dst[-1]); - bytes--; - } - while (bytes >= 2) { - uint16_t s = ao_usb_read_short(base, offset); - dst[0] = s; - dst[1] = s >> 8; - debug_data (" %02x %02x", dst[0], dst[1]); - offset += 2; - dst += 2; - bytes -= 2; - } - if (bytes) { - *dst = ao_usb_read_byte(base, offset); - debug_data (" %02x", dst[0]); - } + debug ("ao_usb_set_configuration\n"); + + /* Set up the INT end point */ + ao_usb_enable_epn(AO_USB_INT_EP, 0, NULL, 0, NULL); + + /* Set up the OUT end point */ + ao_usb_enable_epn(AO_USB_OUT_EP, AO_USB_OUT_SIZE, &ao_usb_out_rx_buffer, 0, NULL); + + /* Set up the IN end point */ + ao_usb_enable_epn(AO_USB_IN_EP, 0, NULL, AO_USB_IN_SIZE, &ao_usb_in_tx_buffer); + + ao_usb_running = 1; } /* Send an IN data packet */ @@ -564,12 +364,6 @@ ao_usb_ep0_flush(void) { uint8_t this_len; - /* Check to see if the endpoint is still busy */ - if (ao_usb_epr_stat_tx(lpc_usb.epr[0]) == USB_USB_EPR_STAT_TX_VALID) { - debug("EP0 not accepting IN data\n"); - return; - } - this_len = ao_usb_ep0_in_len; if (this_len > AO_USB_CONTROL_SIZE) this_len = AO_USB_CONTROL_SIZE; @@ -580,34 +374,43 @@ ao_usb_ep0_flush(void) ao_usb_ep0_in_len -= this_len; debug_data ("Flush EP0 len %d:", this_len); - ao_usb_write(ao_usb_ep0_in_data, ao_usb_ep0_tx_buffer, 0, this_len); + memcpy(ao_usb_ep0_tx_buffer, ao_usb_ep0_in_data, this_len); debug_data ("\n"); ao_usb_ep0_in_data += this_len; /* Mark the endpoint as TX valid to send the packet */ - ao_usb_bdt[AO_USB_CONTROL_EPR].single.count_tx = this_len; - ao_usb_set_stat_tx(AO_USB_CONTROL_EPR, USB_USB_EPR_STAT_TX_VALID); - debug ("queue tx. epr 0 now %08x\n", lpc_usb.epr[AO_USB_CONTROL_EPR]); + ao_usb_set_ep(ao_usb_ep0_in(), ao_usb_ep0_tx_buffer, this_len); + debug ("queue tx. 0 now %08x\n", *ao_usb_ep0_in()); } /* Read data from the ep0 OUT fifo */ static void ao_usb_ep0_fill(void) { - uint16_t len = ao_usb_bdt[0].single.count_rx & USB_USB_BDT_COUNT_RX_COUNT_RX_MASK; + uint16_t len; + uint8_t *rx_buffer; + + /* Pull all of the data out of the packet */ + if (lpc_usb.devcmdstat & (1 << LPC_USB_DEVCMDSTAT_SETUP)) { + rx_buffer = ao_usb_ep0_setup_buffer; + len = 8; + } else { + rx_buffer = ao_usb_ep0_rx_buffer; + len = AO_USB_CONTROL_SIZE - ao_usb_ep_count(ao_usb_ep0_out()); + } if (len > ao_usb_ep0_out_len) len = ao_usb_ep0_out_len; ao_usb_ep0_out_len -= len; - /* Pull all of the data out of the packet */ debug_data ("Fill EP0 len %d:", len); - ao_usb_read(ao_usb_ep0_out_data, ao_usb_ep0_rx_buffer, 0, len); + memcpy(ao_usb_ep0_out_data, rx_buffer, len); debug_data ("\n"); ao_usb_ep0_out_data += len; /* ACK the packet */ - ao_usb_set_stat_rx(0, USB_USB_EPR_STAT_RX_VALID); + ao_usb_set_ep(ao_usb_ep0_out(), ao_usb_ep0_rx_buffer, AO_USB_CONTROL_SIZE); + lpc_usb.devcmdstat |= (1 << LPC_USB_DEVCMDSTAT_SETUP); } static void @@ -772,55 +575,109 @@ ao_usb_ep0_setup(void) ao_usb_ep0_in_start(ao_usb_setup.length); } -/* End point 0 receives all of the control messages. */ static void -ao_usb_ep0(void) +ao_usb_ep0_handle(uint8_t receive) { - uint8_t intx, udint; + ao_usb_ep0_receive = 0; - debug ("usb task started\n"); - ao_usb_ep0_state = AO_USB_EP0_IDLE; - for (;;) { - uint8_t receive; - ao_arch_critical( - while (!(receive = ao_usb_ep0_receive)) - ao_sleep(&ao_usb_ep0_receive); - ao_usb_ep0_receive = 0; - ); - - if (receive & AO_USB_EP0_GOT_RESET) { - debug ("\treset\n"); - ao_usb_set_ep0(); - continue; - } - if (receive & AO_USB_EP0_GOT_SETUP) { - debug ("\tsetup\n"); - ao_usb_ep0_setup(); - } - if (receive & AO_USB_EP0_GOT_RX_DATA) { - debug ("\tgot rx data\n"); - if (ao_usb_ep0_state == AO_USB_EP0_DATA_OUT) { - ao_usb_ep0_fill(); - if (ao_usb_ep0_out_len == 0) { - ao_usb_ep0_state = AO_USB_EP0_DATA_IN; - ao_usb_ep0_in_start(0); - } + if (receive & AO_USB_EP0_GOT_RESET) { + debug ("\treset\n"); + ao_usb_set_ep0(); + return; + } + if (receive & AO_USB_EP0_GOT_SETUP) { + debug ("\tsetup\n"); + ao_usb_ep0_setup(); + } + if (receive & AO_USB_EP0_GOT_RX_DATA) { + debug ("\tgot rx data\n"); + if (ao_usb_ep0_state == AO_USB_EP0_DATA_OUT) { + ao_usb_ep0_fill(); + if (ao_usb_ep0_out_len == 0) { + ao_usb_ep0_state = AO_USB_EP0_DATA_IN; + ao_usb_ep0_in_start(0); } } - if (receive & AO_USB_EP0_GOT_TX_ACK) { - debug ("\tgot tx ack\n"); - - /* Wait until the IN packet is received from addr 0 - * before assigning our local address - */ - if (ao_usb_address_pending) - ao_usb_set_address(ao_usb_address); - if (ao_usb_ep0_state == AO_USB_EP0_DATA_IN) - ao_usb_ep0_flush(); + } + if (receive & AO_USB_EP0_GOT_TX_ACK) { + debug ("\tgot tx ack\n"); + + /* Wait until the IN packet is received from addr 0 + * before assigning our local address + */ + if (ao_usb_address_pending) + ao_usb_set_address(ao_usb_address); + if (ao_usb_ep0_state == AO_USB_EP0_DATA_IN) + ao_usb_ep0_flush(); + } +} + +static uint16_t control_count; +static uint16_t int_count; +static uint16_t in_count; +static uint16_t out_count; +static uint16_t reset_count; + +void +lpc_usb_irq_isr(void) +{ + uint32_t intstat = lpc_usb.intstat & lpc_usb.inten; + + lpc_usb.intstat = intstat; + /* Handle EP0 OUT packets */ + if (intstat & (1 << LPC_USB_INT_EPOUT(0))) { + if (lpc_usb.devcmdstat & (1 << LPC_USB_DEVCMDSTAT_SETUP)) + ao_usb_ep0_receive |= AO_USB_EP0_GOT_SETUP; + else + ao_usb_ep0_receive |= AO_USB_EP0_GOT_RX_DATA; + + ao_usb_ep0_handle(ao_usb_ep0_receive); + } + + /* Handle EP0 IN packets */ + if (intstat & (1 << LPC_USB_INT_EPIN(0))) { + ao_usb_ep0_receive |= AO_USB_EP0_GOT_TX_ACK; + + ao_usb_ep0_handle(ao_usb_ep0_receive); + } + + + /* Handle OUT packets */ + if (intstat & (1 << LPC_USB_INT_EPOUT(AO_USB_OUT_EP))) { + ++out_count; + _rx_dbg1("RX ISR", *ao_usb_epn_out(AO_USB_OUT_EP)); + ao_usb_out_avail = 1; + _rx_dbg0("out avail set"); + ao_wakeup(&ao_stdin_ready); + _rx_dbg0("stdin awoken"); + } + + /* Handle IN packets */ + if (intstat & (1 << LPC_USB_INT_EPIN(AO_USB_IN_EP))) { + ++in_count; + _tx_dbg1("TX ISR", *ao_usb_epn_in(AO_USB_IN_EP)); + ao_usb_in_pending = 0; + ao_wakeup(&ao_usb_in_pending); + } + + /* NAK all INT EP IN packets */ + if (intstat & (1 << LPC_USB_INT_EPIN(AO_USB_INT_EP))) { + ; + } + + /* Check for reset */ + if (intstat & (1 << LPC_USB_INT_DEV)) { + if (lpc_usb.devcmdstat & (1 << LPC_USB_DEVCMDSTAT_DRES_C)) + { + lpc_usb.devcmdstat |= (1 << LPC_USB_DEVCMDSTAT_DRES_C); + ao_usb_ep0_receive |= AO_USB_EP0_GOT_RESET; + ao_usb_ep0_handle(ao_usb_ep0_receive); } } } + + /* Queue the current IN buffer for transmission */ static void _ao_usb_in_send(void) @@ -832,10 +689,9 @@ _ao_usb_in_send(void) ao_usb_in_pending = 1; if (ao_usb_tx_count != AO_USB_IN_SIZE) ao_usb_in_flushed = 1; - ao_usb_write(ao_usb_tx_buffer, ao_usb_in_tx_buffer, 0, ao_usb_tx_count); - ao_usb_bdt[AO_USB_IN_EPR].single.count_tx = ao_usb_tx_count; + memcpy(ao_usb_in_tx_buffer, ao_usb_tx_buffer, ao_usb_tx_count); + ao_usb_set_ep(ao_usb_epn_in(AO_USB_IN_EP), ao_usb_in_tx_buffer, ao_usb_tx_count); ao_usb_tx_count = 0; - _ao_usb_set_stat_tx(AO_USB_IN_EPR, USB_USB_EPR_STAT_TX_VALID); _tx_dbg0("in_send end"); } @@ -905,17 +761,17 @@ _ao_usb_out_recv(void) _rx_dbg0("out_recv top"); ao_usb_out_avail = 0; - ao_usb_rx_count = ao_usb_bdt[AO_USB_OUT_EPR].single.count_rx & USB_USB_BDT_COUNT_RX_COUNT_RX_MASK; + ao_usb_rx_count = AO_USB_OUT_SIZE - ao_usb_epn_out_count(AO_USB_OUT_EP); _rx_dbg1("out_recv count", ao_usb_rx_count); debug ("recv %d\n", ao_usb_rx_count); debug_data("Fill OUT len %d:", ao_usb_rx_count); - ao_usb_read(ao_usb_rx_buffer, ao_usb_out_rx_buffer, 0, ao_usb_rx_count); + memcpy(ao_usb_rx_buffer, ao_usb_out_rx_buffer, ao_usb_rx_count); debug_data("\n"); ao_usb_rx_pos = 0; /* ACK the packet */ - _ao_usb_set_stat_rx(AO_USB_OUT_EPR, USB_USB_EPR_STAT_RX_VALID); + ao_usb_set_epn_out(AO_USB_OUT_EP, ao_usb_out_rx_buffer, AO_USB_OUT_SIZE); } int @@ -960,17 +816,25 @@ void ao_usb_disable(void) { ao_arch_block_interrupts(); - lpc_usb.cntr = (1 << USB_USB_CNTR_FRES); - lpc_usb.istr = 0; - /* Disable USB pull-up */ - lpc_syscfg.pmc &= ~(1 << USB_SYSCFG_PMC_USB_PU); + /* Disable interrupts */ + lpc_usb.inten = 0; + + lpc_nvic_clear_enable(LPC_ISR_USB_IRQ_POS); - /* Switch off the device */ - lpc_usb.cntr = (1 << USB_USB_CNTR_PDWN) | (1 << USB_USB_CNTR_FRES); + /* Disable the device */ + lpc_usb.devcmdstat = 0; + + /* Turn off USB clock */ + lpc_scb.usbclkdiv = 0; + + /* Disable USB PHY */ + lpc_scb.pdruncfg |= (1 << LPC_SCB_PDRUNCFG_USBPAD_PD); + + /* Disable USB registers and RAM */ + lpc_scb.sysahbclkctrl &= ~((1 << LPC_SCB_SYSAHBCLKCTRL_USB) | + (1 << LPC_SCB_SYSAHBCLKCTRL_USBRAM)); - /* Disable the interface */ - lpc_rcc.apb1enr &+ ~(1 << USB_RCC_APB1ENR_USBEN); ao_arch_release_interrupts(); } @@ -979,6 +843,23 @@ ao_usb_enable(void) { int t; + /* Enable USB pins */ +#if HAS_USB_CONNECT + lpc_ioconf.pio0_6 = ((LPC_IOCONF_FUNC_USB_CONNECT << LPC_IOCONF_FUNC) | + (LPC_IOCONF_MODE_INACTIVE << LPC_IOCONF_MODE) | + (0 << LPC_IOCONF_HYS) | + (0 << LPC_IOCONF_INV) | + (0 << LPC_IOCONF_OD) | + 0x80); +#endif +#if HAS_USB_VBUS + lpc_ioconf.pio0_3 = ((LPC_IOCONF_FUNC_USB_VBUS << LPC_IOCONF_FUNC) | + (LPC_IOCONF_MODE_INACTIVE << LPC_IOCONF_MODE) | + (0 << LPC_IOCONF_HYS) | + (0 << LPC_IOCONF_INV) | + (0 << LPC_IOCONF_OD) | + 0x80); +#endif /* Enable USB registers and RAM */ lpc_scb.sysahbclkctrl |= ((1 << LPC_SCB_SYSAHBCLKCTRL_USB) | (1 << LPC_SCB_SYSAHBCLKCTRL_USBRAM)); @@ -986,52 +867,55 @@ ao_usb_enable(void) /* Enable USB PHY */ lpc_scb.pdruncfg &= ~(1 << LPC_SCB_PDRUNCFG_USBPAD_PD); + /* Turn on USB PLL */ + lpc_scb.pdruncfg &= ~(1 << LPC_SCB_PDRUNCFG_USBPLL_PD); + + lpc_scb.usbpllclksel = (LPC_SCB_SYSPLLCLKSEL_SEL_SYSOSC << LPC_SCB_SYSPLLCLKSEL_SEL); + lpc_scb.usbpllclkuen = (1 << LPC_SCB_USBPLLCLKUEN_ENA); + lpc_scb.usbpllclkuen = (0 << LPC_SCB_USBPLLCLKUEN_ENA); + lpc_scb.usbpllclkuen = (1 << LPC_SCB_USBPLLCLKUEN_ENA); + while (!(lpc_scb.usbpllclkuen & (1 << LPC_SCB_USBPLLCLKUEN_ENA))) + ; + lpc_scb.usbpllctrl = 0x23; + while (!(lpc_scb.usbpllstat & 1)) + ; + + lpc_scb.usbclksel = 0; + /* Turn on USB clock, use 48MHz clock unchanged */ lpc_scb.usbclkdiv = 1; /* Configure interrupts */ ao_arch_block_interrupts(); - /* Enable interrupts */ - lpc_usb. - /* Route interrupts */ - - lpc_nvic_set_priority(USB_ISR_USB_LP_POS, 3); - lpc_nvic_set_enable(USB_ISR_USB_LP_POS); + /* Route all interrupts to the main isr */ + lpc_usb.introuting = 0; - ao_usb_configuration = 0; - - lpc_usb.cntr = (1 << USB_USB_CNTR_FRES); + /* Configure NVIC */ - /* Clear the power down bit */ - lpc_usb.cntr = 0; + lpc_nvic_set_enable(LPC_ISR_USB_IRQ_POS); + lpc_nvic_set_priority(LPC_ISR_USB_IRQ_POS, 0); /* Clear any spurious interrupts */ - lpc_usb.istr = 0; + lpc_usb.intstat = 0xffffffff; debug ("ao_usb_enable\n"); /* Enable interrupts */ - lpc_usb.cntr = ((1 << USB_USB_CNTR_CTRM) | - (0 << USB_USB_CNTR_PMAOVRM) | - (0 << USB_USB_CNTR_ERRM) | - (0 << USB_USB_CNTR_WKUPM) | - (0 << USB_USB_CNTR_SUSPM) | - (1 << USB_USB_CNTR_RESETM) | - (0 << USB_USB_CNTR_SOFM) | - (0 << USB_USB_CNTR_ESOFM) | - (0 << USB_USB_CNTR_RESUME) | - (0 << USB_USB_CNTR_FSUSP) | - (0 << USB_USB_CNTR_LP_MODE) | - (0 << USB_USB_CNTR_PDWN) | - (0 << USB_USB_CNTR_FRES)); + lpc_usb.inten = ((1 << LPC_USB_INT_EPOUT(0)) | + (1 << LPC_USB_INT_EPIN(0)) | + (1 << LPC_USB_INT_EPIN(AO_USB_INT_EP)) | + (1 << LPC_USB_INT_EPOUT(AO_USB_OUT_EP)) | + (1 << LPC_USB_INT_EPIN(AO_USB_IN_EP)) | + (1 << LPC_USB_INT_DEV)); ao_arch_release_interrupts(); + lpc_usb.devcmdstat = 0; for (t = 0; t < 1000; t++) ao_arch_nop(); - /* Enable USB pull-up */ - lpc_syscfg.pmc |= (1 << USB_SYSCFG_PMC_USB_PU); + + ao_usb_set_ep0(); } #if USB_ECHO @@ -1070,7 +954,6 @@ ao_usb_init(void) ao_usb_enable(); debug ("ao_usb_init\n"); - ao_add_task(&ao_usb_task, ao_usb_ep0, "usb"); #if USB_ECHO ao_add_task(&ao_usb_echo_task, ao_usb_echo, "usb echo"); #endif @@ -1091,7 +974,7 @@ struct ao_usb_dbg { uint32_t primask; #if TX_DBG uint16_t in_count; - uint32_t in_epr; + uint32_t in_ep; uint32_t in_pending; uint32_t tx_count; uint32_t in_flushed; @@ -1100,13 +983,13 @@ struct ao_usb_dbg { uint8_t rx_count; uint8_t rx_pos; uint8_t out_avail; - uint32_t out_epr; + uint32_t out_ep; #endif }; -#define NUM_USB_DBG 128 +#define NUM_USB_DBG 8 -static struct ao_usb_dbg dbg[128]; +static struct ao_usb_dbg dbg[NUM_USB_DBG]; static int dbg_i; static void _dbg(int line, char *msg, uint32_t value) @@ -1119,7 +1002,7 @@ static void _dbg(int line, char *msg, uint32_t value) dbg[dbg_i].primask = primask; #if TX_DBG dbg[dbg_i].in_count = in_count; - dbg[dbg_i].in_epr = lpc_usb.epr[AO_USB_IN_EPR]; + dbg[dbg_i].in_ep = *ao_usb_epn_in(AO_USB_IN_EP); dbg[dbg_i].in_pending = ao_usb_in_pending; dbg[dbg_i].tx_count = ao_usb_tx_count; dbg[dbg_i].in_flushed = ao_usb_in_flushed; @@ -1128,7 +1011,7 @@ static void _dbg(int line, char *msg, uint32_t value) dbg[dbg_i].rx_count = ao_usb_rx_count; dbg[dbg_i].rx_pos = ao_usb_rx_pos; dbg[dbg_i].out_avail = ao_usb_out_avail; - dbg[dbg_i].out_epr = lpc_usb.epr[AO_USB_OUT_EPR]; + dbg[dbg_i].out_ep = *ao_usb_epn_out(AO_USB_OUT_EP); #endif if (++dbg_i == NUM_USB_DBG) dbg_i = 0; diff --git a/src/lpc/lpc.h b/src/lpc/lpc.h index 4e229838..4141f356 100644 --- a/src/lpc/lpc.h +++ b/src/lpc/lpc.h @@ -116,7 +116,7 @@ extern struct lpc_ioconf lpc_ioconf; #define LPC_IOCONF_FUNC_SSEL0 1 #define LPC_IOCONF_FUNC_CT16B0_CAP0 2 -/* PIO0_3 +/* PIO0_3 */ #define LPC_IOCONF_FUNC_PIO0_3 0 #define LPC_IOCONF_FUNC_USB_VBUS 1 @@ -395,7 +395,7 @@ struct lpc_scb { vuint32_t syspllclksel; /* 0x40 */ vuint32_t syspllclkuen; vuint32_t usbpllclksel; - vuint32_t usbplllclkuen; + vuint32_t usbpllclkuen; uint32_t r50[8]; @@ -600,8 +600,13 @@ extern struct lpc_scb lpc_scb; #define LPC_SCB_USBCLKUEN_ENA 0 #define LPC_SCB_USBCLKDIV_DIV 0 -#define LPC_SCB_CLKOUTSEL_ -#define LPC_SCB_CLKOUTUEN_ +#define LPC_SCB_CLKOUTSEL_SEL 0 +#define LPC_SCB_CLKOUTSEL_SEL_IRC 0 +#define LPC_SCB_CLKOUTSEL_SEL_SYSOSC 1 +#define LPC_SCB_CLKOUTSEL_SEL_LF 2 +#define LPC_SCB_CLKOUTSEL_SEL_MAIN_CLOCK 3 + +#define LPC_SCB_CLKOUTUEN_ENA 0 #define LPC_SCB_PDRUNCFG_IRCOUT_PD 0 #define LPC_SCB_PDRUNCFG_IRC_PD 1 @@ -823,6 +828,7 @@ struct lpc_usb { vuint32_t inten; vuint32_t intsetstat; vuint32_t introuting; + uint32_t r30; vuint32_t eptoggle; } lpc_usb; @@ -884,18 +890,11 @@ extern struct lpc_usb lpc_usb; #define LPC_USB_EPBUFCFG_BUF_SB(ep) (ep) -#define LPC_USB_INTSTAT_EP0OUT 0 -#define LPC_USB_INTSTAT_EP0IN 1 -#define LPC_USB_INTSTAT_EP1OUT 2 -#define LPC_USB_INTSTAT_EP1IN 3 -#define LPC_USB_INTSTAT_EP2OUT 4 -#define LPC_USB_INTSTAT_EP2IN 5 -#define LPC_USB_INTSTAT_EP3OUT 6 -#define LPC_USB_INTSTAT_EP3IN 7 -#define LPC_USB_INTSTAT_EP4OUT 8 -#define LPC_USB_INTSTAT_EP4IN 9 -#define LPC_USB_INTSTAT_FRAME_INT 30 -#define LPC_USB_INTSTAT_DEV_INT 31 +#define LPC_USB_INT_EPOUT(ep) ((ep) << 1) +#define LPC_USB_INT_EPIN(ep) (((ep) << 1) + 1) + +#define LPC_USB_INT_FRAME 30 +#define LPC_USB_INT_DEV 31 #define LPC_USB_INTIN_EP_INT_EN(ep) (ep) #define LPC_USB_INTIN_FRAME_INT_EN 30 @@ -911,34 +910,34 @@ extern struct lpc_usb lpc_usb; #define LPC_USB_EPTOGGLE_TOGGLE(ep) (ep) -struct lpc_usb_ep { - vuint16_t buffer_offset; - vuint16_t buffer_status_nbytes; -}; - struct lpc_usb_epn { - struct lpc_usb_ep out[2]; - struct lpc_usb_ep in[2]; + vuint32_t out[2]; + vuint32_t in[2]; }; struct lpc_usb_endpoint { - struct lpc_usb_ep ep0_out; - vuint16_t setup_offset; - vuint16_t reserved_06; - struct lpc_usb_ep ep0_in; - vuint16_t reserved_0c; - vuint16_t reserved_0e; + vuint32_t ep0_out; + vuint32_t setup; + vuint32_t ep0_in; + vuint32_t reserved_0c; struct lpc_usb_epn epn[4]; }; -#define LPC_USB_EP_STATUS_ACTIVE 15 -#define LPC_USB_EP_STATUS_DISABLED 14 -#define LPC_USB_EP_STATUS_STALL 13 -#define LPC_USB_EP_STATUS_TOGGLE_RESET 12 -#define LPC_USB_EP_STATUS_RATE_FEEDBACK 11 -#define LPC_USB_EP_STATUS_ENDPOINT_TYPE 10 -#define LPC_USB_EP_STATUS_OFFSET 0 -#define LPC_USB_EP_STATUS_OFFSET_MASK 0x3ff +/* Assigned in registers.ld to point at the base + * of USB ram + */ + +extern uint8_t lpc_usb_sram[]; + +#define LPC_USB_EP_ACTIVE 31 +#define LPC_USB_EP_DISABLED 30 +#define LPC_USB_EP_STALL 29 +#define LPC_USB_EP_TOGGLE_RESET 28 +#define LPC_USB_EP_RATE_FEEDBACK 27 +#define LPC_USB_EP_ENDPOINT_ISO 26 +#define LPC_USB_EP_NBYTES 16 +#define LPC_USB_EP_NBYTES_MASK 0x3ff +#define LPC_USB_EP_OFFSET 0 #define LPC_ISR_PIN_INT0_POS 0 #define LPC_ISR_PIN_INT1_POS 1 @@ -1039,4 +1038,20 @@ lpc_nvic_get_priority(int irq) { return (lpc_nvic.ipr[IRQ_PRIO_REG(irq)] >> IRQ_PRIO_BIT(irq)) & IRQ_PRIO_MASK(0); } +struct arm_scb { + vuint32_t cpuid; + vuint32_t icsr; + uint32_t reserved08; + vuint32_t aircr; + + vuint32_t scr; + vuint32_t ccr; + uint32_t reserved18; + vuint32_t shpr2; + + vuint32_t shpr3; +}; + +extern struct arm_scb arm_scb; + #endif /* _LPC_H_ */ diff --git a/src/lpc/registers.ld b/src/lpc/registers.ld index 51a0612f..0201e55f 100644 --- a/src/lpc/registers.ld +++ b/src/lpc/registers.ld @@ -9,3 +9,5 @@ lpc_usb = 0x40080000; lpc_gpio = 0x50000000; lpc_systick = 0xe000e000; lpc_nvic = 0xe000e100; +arm_scb = 0xe000ed00; +lpc_usb_sram = 0x20004000; diff --git a/src/lpcxpresso/Makefile b/src/lpcxpresso/Makefile index bac222cc..3745f283 100644 --- a/src/lpcxpresso/Makefile +++ b/src/lpcxpresso/Makefile @@ -23,8 +23,10 @@ ALTOS_SRC = \ ao_panic.c \ ao_led_lpc.c \ ao_task.c \ + ao_cmd.c \ ao_timer_lpc.c \ ao_serial_lpc.c \ + ao_usb_lpc.c \ ao_stdio.c PRODUCT=LpcDemo-v0.0 diff --git a/src/lpcxpresso/ao_demo.c b/src/lpcxpresso/ao_demo.c index eae9503e..0c931611 100644 --- a/src/lpcxpresso/ao_demo.c +++ b/src/lpcxpresso/ao_demo.c @@ -15,24 +15,8 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -#include "ao.h" - -struct ao_task demo_task; - -static void demo(void) { - for (;;) { - ao_delay(100); - ao_led_toggle(AO_LED_RED); - } -} - -static struct ao_task serial_task; - -static void serial(void) { - for (;;) { - printf ("hello, world\n"); - } -} +#include +#include int main(void) @@ -44,12 +28,10 @@ main(void) ao_timer_init(); ao_serial_init(); - + ao_usb_init(); + ao_cmd_init(); ao_task_init(); - ao_add_task(&demo_task, demo, "demo"); - ao_add_task(&serial_task, serial, "serial"); - ao_start_scheduler(); for (;;) { diff --git a/src/lpcxpresso/ao_pins.h b/src/lpcxpresso/ao_pins.h index 7748f73c..c0074ce2 100644 --- a/src/lpcxpresso/ao_pins.h +++ b/src/lpcxpresso/ao_pins.h @@ -34,7 +34,10 @@ #define LEDS_AVAILABLE AO_LED_RED -#define HAS_USB 0 +#define HAS_USB 1 + +#define HAS_USB_CONNECT 1 +#define HAS_USB_VBUS 1 #define PACKET_HAS_SLAVE 0 -- 2.30.2