The file UsbHwLPC1xxx.fth contains the USB hardware layer for NXP LPC1xxx and some LPC4xxx devices. The file UsbHwLPC2xxx.fth is very similar and contains code for NXP LPC2xxx devices.
DMA operation is supported if the equate usbDMA?
is
set non-zero in the USB configuration file, e.g. MscConfig.fth.
Use of DMA is strongly recommended.
For most real-time applications the benefit of DMA operation
is the considerable reduction of interrupt overhead at the
expense of code size. If even this is unacceptable, consider
the following solutions.
: EPaddr \ ep# -- physaddr
Translate the endpoint number to a physical address. Bit 7
of the endpoint number ep# (0..15) is set if the write
buffer is required.
1 equ usbDMA? \ -- flag
Set non-zero if the USB hardware is to use DMA for bulk and
isochronous transfers. The definition in this file is only
used if not previously defined.
Use of DMA is strongly recommended.
The USB hardware contains its own DMA controller. Whether
this is used is set by the equate usbDMA?
in the USB
configuration file. Each endpoint that uses DMA must
define at least one DMA descriptor and its type.
32 cells buffer: UDCA \ -- addr
USB DMA communication area. UDCA
is only defined here
if it has not already been defined.
create UDCAcfg \ -- addr
A table of device descriptors used to initialise the
UDCA
.
create EpDmaCfg \ -- addr
A table containing a byte per endpoint. The byte indicates
how the endpoint is used with DMA:
0 |
no DMA |
16 |
Bulk or interrupt endpoint |
20 |
Isochronous endpoint. |
DMA use is set at compile time. The following INTERPRETER
words are used.
: BulkDD: \ ep# -- ; e.g. $0x or $8x
Creates a bulk DMA Descriptor in the URAMP
section, and adds it to the UDCAcfg
template.
: IntDD: \ ep# -- ; e.g. $0x or $8x
Creates an interrupt DMA Descriptor in the URAMP
section, and adds it to the UDCAcfg
template.
: IsoDD: \ ep# -- ; e.g. $0x or $8x
Creates an Isochronous DMA Descriptor in the URAMP
section,
and adds it to the UDCAcfg
template.
: resetDD \ physaddr dd --
Reset a device descriptor to No_Packet state. The DMA
buffer address, length and max packet size are all zero.
See LPC23xx User Manual, Chapter 13, 15.5.6.
: initEPdma \ physaddr --
Set up the DMA for the given endpoint (0..31) and apply
resetDD
.
: initUSBdma \ --
Initialise the USB DMA.
: setEPdma \ caddr len ep# --
Set the next transfer for an endpoint ($0x/$8x).
: #EPtrans \ ep# -- len
Return the number of bytes transferred on this endpoint.
The return value is only valid after a transfer is complete.
: enEPdma \ ep# --
Enable endpoint DMA.
: disEPdma \ ep# --
Disable endpoint DMA.
create ^USBdev \ -- addr
Holds the address of the USB device peripheral.
: EpIntSt@ \ -- x
Read the endpoint interrupt status register.
: EpIntClr! \ x --
Write the endpoint interrupt clear register.
: DevIntSt@ \ -- x
Read the device interrupt status register.
: CmdData@ \ -- x
Read the command data register.
: EpRe! \ x --
Write the EpRe register.
The USB Protocol Engine is triggered by writing to the
UsbDevCmdCode
register. Commands are in the form:
00ppcc00
where pp is the command phase and cc is the command code. For more details, read the source code.
Commands for the LPC2xxx USB controller are 32 bit items of the form $aabb:0500. When data is also written the 8 bit data is written as a 32 bit item of the form $00bb:0100. When a data byte is to be read, the read is performed by reissuing the command in the form $aabb:0200, and waiting for the CDFULL interrupt rather than the CCEMTY interrupt.
: WrCmd \ cmd --
Write cmd to the CmdCode register.
: WrCmdDat \ cmd val --
Write cmd followed by val to the CmdCode register.
: RdCmdDat \ cmd -- val
Write a command and read the data.
This section contains an array of endpoint handlers and default actions for other operations which are hardware dependent.
create EPxts \ -- addr
Holds the xts of the 16 endpoint handler words. The action
of each handler must have the stack effect below:
event --
: EPhandler \ event u --
Run the endpoint handler associated with endpoint u,
where endpoints are numbered 0..15. Each endpoint handler
is passed an event type which allows it to determine what
it has to do. The action of each handler must have the stack
effect below.
event --
: SetEPhandler \ xt ep# --
Install the endpoint handler for endpoint ep#.
Used during interpretation.
0 value UsbDevSt \ -- x
USB device Status.
: USBsuspend \ --
Suspend operations are performed by the hardware. This
is a hook for installing actions such as toggling an LED.
: USBresume \ --
Resume operations are performed by the hardware. This
is a hook for installing actions such as toggling an LED.
: USBconnect \ --
Connect to the USB bus.
: USBdisconnect \ --
Disconnect from the USB bus.
: USBWakeUp \ --
Called automatically on USB Remote Wakeup.
: USBSetAddress \ addr --
Set the USB assigned address in the protocol engine.
: WaitEPrlzed \ --
Wait for the EP_RLZED interrupt status and clear it.
: USBConfigure \ cfg -- ; 0=unconfigure
Set the SIE configuration state.
: USBConfigEP \ desc --
Configure USB Endpoint according to Descriptor.
: USBConfig2EP \ desc ep# -- desc
Configure USB Endpoint according to Descriptor and EndPoint.
: USBDirCtrlEP \ dir -- ; 0=out
This word is a dummy for this hardware.
: USBEnableEP \ ep# -- ; bit7=dir, bits3:0=num
Enable the endpoint.
: USBDisableEP \ ep# -- ; bit7=dir, bits3:0=num
Disable the endpoint.
: USBResetEP \ ep# -- ; bit7=dir, bits3:0=num
Reset the endpoint.
variable SieModeMask \ -- addr
A shadow variable that holds the last mode mask set.
: setSIEmode \ mask --
Set the USB device mode register in the SIE. A shadow
variable is used to hold the current state.
: +BulkNAKin \ --
Enable NAK interrupts on bulk IN endpoints.
All other SIE mode bits are left alone.
: -BulkNAKin \ --
Disable NAK interrupts on bulk IN endpoints.
All other SIE mode bits are left alone.
: +BulkNAKout \ --
Enable NAK interrupts on bulk OUT endpoints.
All other SIE mode bits are left alone.
: -BulkNAKout \ --
Disable NAK interrupts on bulk OUT endpoints.
All other SIE mode bits are left alone.
: USBSetStallEP \ ep# -- ; bit7=dir, bits3:0=num
Stall the endpoint. This word must clear the relevant
bit in UsbEpHalt
.
: USBClrStallEP \ ep# -- ; bit7=dir, bits3:0=num
Clear the endpoint stall. This word must clear the relevant
bit in UsbEpHalt
, and should ensure that bulk IN/OUT NAKs cause
interrupts.
code portl> \ caddr len port --
Read the port into the the memory block a cell at a time.
If caddr is aligned, the data is stored cell by cell,
otherwise it is assembled a byte at a time before being sent
to the port.
: USBReadEP \ ep# addr -- #read ; bit7=dir, bits3:0=num
Read endpoint data from endpoint ep# to addr.
It will be faster if addr is aligned. Return the
number of bytes read.
Note that data is transferred in units of four bytes, so
the buffer must be large enough to accommodate up to three
extra bytes.
code >portl \ caddr len port --
Transfer the memory block to the port a cell at a time.
If caddr is aligned, the data is fetched cell by cell,
otherwise it is assembled a byte at a time before being sent
to the port.
: USBWriteEP \ ep# addr len -- cnt
Write data addr/len to host from endpoint ep#.
Return the number of bytes written.
: hwUSBreset \ --
Reset the USB device hardware after access has been enabled.
: USBswReset \ --
The action performed for a software reset of the USB, either
at reset or in response to a USB reset.
: waitCmdData \ -- x
Wait for CDFULL and read the data
: doEPslow \ --
Process an EP_SLOW interrupt.
: doDmaEOT \ --
Handle DMA End Of Transfer interrupt.
: doDmaNDDReq \ --
Handle DMA New DD request interrupt.
USB Ssytem Errors are AHB bus errors. As yet, the AHB bus configuration registers are undocumented. Consequently there is no point in trying to handle these errors, and the code framework to do so is commented out.
: doDmaSysErr \ --
Handle DMA System Error interrupt.
: doUSBint \ disr -- disr'
The primary word called from USBinterrupt
below.
Processes DEV_STAT, EP_SLOW and FRAME interrupt sources,
ignoring and clearing all others. If DMA is enabled, DMA
interrupts are also processed.
: USBinterrupt \ --
The USB interrupt handler. It calls doUSBint
above to
permit better factoring.
' USBinterrupt USB_vec# EXC: USB_ISR \ -- addr
The entry point for the USB interrupt.
: USBintInit \ --
Initialise USB hardware interrupt handler.
: InitUSB \ --
Initialise the USB hardware.
: startUSB \ --
Start the USB system. This word gives more control to devices
that have VBUS control. If such devices are rebooted without
power down, they may/will need to perform a USBdisconnect
operation as part of the start up sequence. A disconnect,
delay, connect sequence is part of startUSB
.
Under some conditions, normally after testing a faulty USB device, the Windows USB system can become faulty. During device development, rebooting your PC will be a common occurrence.
When using console debug messages, note that you must not use
serial drivers with queued output. These use PAUSE
which must not be called from an interrupt handler.