mirror of https://github.com/ARMmbed/mbed-os.git
Add USBPhy for the LPC17xx
Move the LPC17xx USB driver files from mbed-os\features\unsupported\USBDevice\targets\TARGET_NXP and update them to match the new USBPhy API.pull/6479/head
parent
17bc923eb6
commit
cccbcdee0d
|
@ -0,0 +1,97 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2018-2018 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#define NUMBER_OF_LOGICAL_ENDPOINTS (16)
|
||||
#define NUMBER_OF_PHYSICAL_ENDPOINTS (NUMBER_OF_LOGICAL_ENDPOINTS * 2)
|
||||
|
||||
/* Define physical endpoint numbers */
|
||||
|
||||
/* Endpoint No. Type(s) MaxPacket DoubleBuffer */
|
||||
/* ---------------- ------------ ---------- --- */
|
||||
#define EP0OUT (0x00) /* Control 64 No */
|
||||
#define EP0IN (0x80) /* Control 64 No */
|
||||
#define EP1OUT (0x01) /* Interrupt 64 No */
|
||||
#define EP1IN (0x81) /* Interrupt 64 No */
|
||||
#define EP2OUT (0x02) /* Bulk 64 Yes */
|
||||
#define EP2IN (0x82) /* Bulk 64 Yes */
|
||||
#define EP3OUT (0x03) /* Isochronous 1023 Yes */
|
||||
#define EP3IN (0x83) /* Isochronous 1023 Yes */
|
||||
#define EP4OUT (0x04) /* Interrupt 64 No */
|
||||
#define EP4IN (0x84) /* Interrupt 64 No */
|
||||
#define EP5OUT (0x05) /* Bulk 64 Yes */
|
||||
#define EP5IN (0x85) /* Bulk 64 Yes */
|
||||
#define EP6OUT (0x06) /* Isochronous 1023 Yes */
|
||||
#define EP6IN (0x86) /* Isochronous 1023 Yes */
|
||||
#define EP7OUT (0x07) /* Interrupt 64 No */
|
||||
#define EP7IN (0x87) /* Interrupt 64 No */
|
||||
#define EP8OUT (0x08) /* Bulk 64 Yes */
|
||||
#define EP8IN (0x88) /* Bulk 64 Yes */
|
||||
#define EP9OUT (0x09) /* Isochronous 1023 Yes */
|
||||
#define EP9IN (0x89) /* Isochronous 1023 Yes */
|
||||
#define EP10OUT (0x0A) /* Interrupt 64 No */
|
||||
#define EP10IN (0x8A) /* Interrupt 64 No */
|
||||
#define EP11OUT (0x0B) /* Bulk 64 Yes */
|
||||
#define EP11IN (0x8B) /* Bulk 64 Yes */
|
||||
#define EP12OUT (0x0C) /* Isochronous 1023 Yes */
|
||||
#define EP12IN (0x8C) /* Isochronous 1023 Yes */
|
||||
#define EP13OUT (0x0D) /* Interrupt 64 No */
|
||||
#define EP13IN (0x8D) /* Interrupt 64 No */
|
||||
#define EP14OUT (0x0E) /* Bulk 64 Yes */
|
||||
#define EP14IN (0x8E) /* Bulk 64 Yes */
|
||||
#define EP15OUT (0x0F) /* Bulk 64 Yes */
|
||||
#define EP15IN (0x8F) /* Bulk 64 Yes */
|
||||
|
||||
/* Maximum Packet sizes */
|
||||
|
||||
#define MAX_PACKET_SIZE_EP0 (64)
|
||||
#define MAX_PACKET_SIZE_EP1 (64)
|
||||
#define MAX_PACKET_SIZE_EP2 (64)
|
||||
#define MAX_PACKET_SIZE_EP3 (1023)
|
||||
#define MAX_PACKET_SIZE_EP4 (64)
|
||||
#define MAX_PACKET_SIZE_EP5 (64)
|
||||
#define MAX_PACKET_SIZE_EP6 (1023)
|
||||
#define MAX_PACKET_SIZE_EP7 (64)
|
||||
#define MAX_PACKET_SIZE_EP8 (64)
|
||||
#define MAX_PACKET_SIZE_EP9 (1023)
|
||||
#define MAX_PACKET_SIZE_EP10 (64)
|
||||
#define MAX_PACKET_SIZE_EP11 (64)
|
||||
#define MAX_PACKET_SIZE_EP12 (1023)
|
||||
#define MAX_PACKET_SIZE_EP13 (64)
|
||||
#define MAX_PACKET_SIZE_EP14 (64)
|
||||
#define MAX_PACKET_SIZE_EP15 (64)
|
||||
|
||||
/* Generic endpoints - intended to be portable accross devices */
|
||||
/* and be suitable for simple USB devices. */
|
||||
|
||||
/* Bulk endpoints */
|
||||
#define EPBULK_OUT (EP2OUT)
|
||||
#define EPBULK_IN (EP2IN)
|
||||
#define EPBULK_OUT_callback EP2_OUT_callback
|
||||
#define EPBULK_IN_callback EP2_IN_callback
|
||||
/* Interrupt endpoints */
|
||||
#define EPINT_OUT (EP1OUT)
|
||||
#define EPINT_IN (EP1IN)
|
||||
#define EPINT_OUT_callback EP1_OUT_callback
|
||||
#define EPINT_IN_callback EP1_IN_callback
|
||||
/* Isochronous endpoints */
|
||||
#define EPISO_OUT (EP3OUT)
|
||||
#define EPISO_IN (EP3IN)
|
||||
#define EPISO_OUT_callback EP3_OUT_callback
|
||||
#define EPISO_IN_callback EP3_IN_callback
|
||||
|
||||
#define MAX_PACKET_SIZE_EPBULK (MAX_PACKET_SIZE_EP2)
|
||||
#define MAX_PACKET_SIZE_EPINT (MAX_PACKET_SIZE_EP1)
|
||||
#define MAX_PACKET_SIZE_EPISO (MAX_PACKET_SIZE_EP3)
|
|
@ -0,0 +1,709 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2018-2018 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#if defined(DEVICE_USBDEVICE) && DEVICE_USBDEVICE && \
|
||||
(defined(TARGET_LPC1768) || defined(TARGET_LPC2368) || defined(TARGET_LPC2460))
|
||||
|
||||
#include "USBEndpoints_LPC17_LPC23.h"
|
||||
#include "USBPhyHw.h"
|
||||
#include "usb_phy_api.h"
|
||||
|
||||
|
||||
// Get endpoint direction
|
||||
#define IN_EP(endpoint) ((endpoint) & 1U ? true : false)
|
||||
#define OUT_EP(endpoint) ((endpoint) & 1U ? false : true)
|
||||
|
||||
// Convert physical endpoint number to register bit
|
||||
#define EP(endpoint) (1UL<<DESC_TO_PHY(endpoint))
|
||||
|
||||
#define DESC_TO_PHY(endpoint) ((((endpoint)&0x0F)<<1) | (((endpoint) & 0x80) ? 1:0))
|
||||
#define PHY_TO_DESC(endpoint) (((endpoint)>>1)|(((endpoint)&1)?0x80:0))
|
||||
|
||||
// Power Control for Peripherals register
|
||||
#define PCUSB (1UL<<31)
|
||||
|
||||
// USB Clock Control register
|
||||
#define DEV_CLK_EN (1UL<<1)
|
||||
#define AHB_CLK_EN (1UL<<4)
|
||||
|
||||
// USB Clock Status register
|
||||
#define DEV_CLK_ON (1UL<<1)
|
||||
#define AHB_CLK_ON (1UL<<4)
|
||||
|
||||
// USB Device Interupt registers
|
||||
#define FRAME (1UL<<0)
|
||||
#define EP_FAST (1UL<<1)
|
||||
#define EP_SLOW (1UL<<2)
|
||||
#define DEV_STAT (1UL<<3)
|
||||
#define CCEMPTY (1UL<<4)
|
||||
#define CDFULL (1UL<<5)
|
||||
#define RxENDPKT (1UL<<6)
|
||||
#define TxENDPKT (1UL<<7)
|
||||
#define EP_RLZED (1UL<<8)
|
||||
#define ERR_INT (1UL<<9)
|
||||
|
||||
// USB Control register
|
||||
#define RD_EN (1<<0)
|
||||
#define WR_EN (1<<1)
|
||||
#define LOG_ENDPOINT(endpoint) ((DESC_TO_PHY(endpoint)>>1)<<2)
|
||||
|
||||
// USB Receive Packet Length register
|
||||
#define DV (1UL<<10)
|
||||
#define PKT_RDY (1UL<<11)
|
||||
#define PKT_LNGTH_MASK (0x3ff)
|
||||
|
||||
// Serial Interface Engine (SIE)
|
||||
#define SIE_WRITE (0x01)
|
||||
#define SIE_READ (0x02)
|
||||
#define SIE_COMMAND (0x05)
|
||||
#define SIE_CMD_CODE(phase, data) ((phase<<8)|(data<<16))
|
||||
|
||||
// SIE Command codes
|
||||
#define SIE_CMD_SET_ADDRESS (0xD0)
|
||||
#define SIE_CMD_CONFIGURE_DEVICE (0xD8)
|
||||
#define SIE_CMD_SET_MODE (0xF3)
|
||||
#define SIE_CMD_READ_FRAME_NUMBER (0xF5)
|
||||
#define SIE_CMD_READ_TEST_REGISTER (0xFD)
|
||||
#define SIE_CMD_SET_DEVICE_STATUS (0xFE)
|
||||
#define SIE_CMD_GET_DEVICE_STATUS (0xFE)
|
||||
#define SIE_CMD_GET_ERROR_CODE (0xFF)
|
||||
#define SIE_CMD_READ_ERROR_STATUS (0xFB)
|
||||
|
||||
#define SIE_CMD_SELECT_ENDPOINT(endpoint) (0x00+DESC_TO_PHY(endpoint))
|
||||
#define SIE_CMD_SELECT_ENDPOINT_CLEAR_INTERRUPT(endpoint) (0x40+DESC_TO_PHY(endpoint))
|
||||
#define SIE_CMD_SET_ENDPOINT_STATUS(endpoint) (0x40+DESC_TO_PHY(endpoint))
|
||||
|
||||
#define SIE_CMD_CLEAR_BUFFER (0xF2)
|
||||
#define SIE_CMD_VALIDATE_BUFFER (0xFA)
|
||||
|
||||
// SIE Device Status register
|
||||
#define SIE_DS_CON (1<<0)
|
||||
#define SIE_DS_CON_CH (1<<1)
|
||||
#define SIE_DS_SUS (1<<2)
|
||||
#define SIE_DS_SUS_CH (1<<3)
|
||||
#define SIE_DS_RST (1<<4)
|
||||
|
||||
// SIE Device Set Address register
|
||||
#define SIE_DSA_DEV_EN (1<<7)
|
||||
|
||||
// SIE Configue Device register
|
||||
#define SIE_CONF_DEVICE (1<<0)
|
||||
|
||||
// Select Endpoint register
|
||||
#define SIE_SE_FE (1<<0)
|
||||
#define SIE_SE_ST (1<<1)
|
||||
#define SIE_SE_STP (1<<2)
|
||||
#define SIE_SE_PO (1<<3)
|
||||
#define SIE_SE_EPN (1<<4)
|
||||
#define SIE_SE_B_1_FULL (1<<5)
|
||||
#define SIE_SE_B_2_FULL (1<<6)
|
||||
|
||||
// Set Endpoint Status command
|
||||
#define SIE_SES_ST (1<<0)
|
||||
#define SIE_SES_DA (1<<5)
|
||||
#define SIE_SES_RF_MO (1<<6)
|
||||
#define SIE_SES_CND_ST (1<<7)
|
||||
|
||||
|
||||
static USBPhyHw *instance;
|
||||
|
||||
static volatile int epComplete;
|
||||
|
||||
static void SIECommand(uint32_t command)
|
||||
{
|
||||
// The command phase of a SIE transaction
|
||||
LPC_USB->USBDevIntClr = CCEMPTY;
|
||||
LPC_USB->USBCmdCode = SIE_CMD_CODE(SIE_COMMAND, command);
|
||||
while (!(LPC_USB->USBDevIntSt & CCEMPTY));
|
||||
}
|
||||
|
||||
static void SIEWriteData(uint8_t data)
|
||||
{
|
||||
// The data write phase of a SIE transaction
|
||||
LPC_USB->USBDevIntClr = CCEMPTY;
|
||||
LPC_USB->USBCmdCode = SIE_CMD_CODE(SIE_WRITE, data);
|
||||
while (!(LPC_USB->USBDevIntSt & CCEMPTY));
|
||||
}
|
||||
|
||||
static uint8_t SIEReadData(uint32_t command)
|
||||
{
|
||||
// The data read phase of a SIE transaction
|
||||
LPC_USB->USBDevIntClr = CDFULL;
|
||||
LPC_USB->USBCmdCode = SIE_CMD_CODE(SIE_READ, command);
|
||||
while (!(LPC_USB->USBDevIntSt & CDFULL));
|
||||
return (uint8_t)LPC_USB->USBCmdData;
|
||||
}
|
||||
|
||||
static void SIEsetDeviceStatus(uint8_t status)
|
||||
{
|
||||
// Write SIE device status register
|
||||
SIECommand(SIE_CMD_SET_DEVICE_STATUS);
|
||||
SIEWriteData(status);
|
||||
}
|
||||
|
||||
static uint8_t SIEgetDeviceStatus(void)
|
||||
{
|
||||
// Read SIE device status register
|
||||
SIECommand(SIE_CMD_GET_DEVICE_STATUS);
|
||||
return SIEReadData(SIE_CMD_GET_DEVICE_STATUS);
|
||||
}
|
||||
|
||||
void SIEsetAddress(uint8_t address)
|
||||
{
|
||||
// Write SIE device address register
|
||||
SIECommand(SIE_CMD_SET_ADDRESS);
|
||||
SIEWriteData((address & 0x7f) | SIE_DSA_DEV_EN);
|
||||
}
|
||||
|
||||
static uint8_t SIEselectEndpoint(uint8_t endpoint)
|
||||
{
|
||||
// SIE select endpoint command
|
||||
SIECommand(SIE_CMD_SELECT_ENDPOINT(endpoint));
|
||||
return SIEReadData(SIE_CMD_SELECT_ENDPOINT(endpoint));
|
||||
}
|
||||
|
||||
static uint8_t SIEclearBuffer(void)
|
||||
{
|
||||
// SIE clear buffer command
|
||||
SIECommand(SIE_CMD_CLEAR_BUFFER);
|
||||
return SIEReadData(SIE_CMD_CLEAR_BUFFER);
|
||||
}
|
||||
|
||||
static void SIEvalidateBuffer(void)
|
||||
{
|
||||
// SIE validate buffer command
|
||||
SIECommand(SIE_CMD_VALIDATE_BUFFER);
|
||||
}
|
||||
|
||||
static void SIEsetEndpointStatus(uint8_t endpoint, uint8_t status)
|
||||
{
|
||||
// SIE set endpoint status command
|
||||
SIECommand(SIE_CMD_SET_ENDPOINT_STATUS(endpoint));
|
||||
SIEWriteData(status);
|
||||
}
|
||||
|
||||
static uint16_t SIEgetFrameNumber(void) __attribute__((unused));
|
||||
static uint16_t SIEgetFrameNumber(void)
|
||||
{
|
||||
// Read current frame number
|
||||
uint16_t lowByte;
|
||||
uint16_t highByte;
|
||||
|
||||
SIECommand(SIE_CMD_READ_FRAME_NUMBER);
|
||||
lowByte = SIEReadData(SIE_CMD_READ_FRAME_NUMBER);
|
||||
highByte = SIEReadData(SIE_CMD_READ_FRAME_NUMBER);
|
||||
|
||||
return (highByte << 8) | lowByte;
|
||||
}
|
||||
|
||||
static void SIEconfigureDevice(void)
|
||||
{
|
||||
// SIE Configure device command
|
||||
SIECommand(SIE_CMD_CONFIGURE_DEVICE);
|
||||
SIEWriteData(SIE_CONF_DEVICE);
|
||||
}
|
||||
|
||||
static void SIEunconfigureDevice(void)
|
||||
{
|
||||
// SIE Configure device command
|
||||
SIECommand(SIE_CMD_CONFIGURE_DEVICE);
|
||||
SIEWriteData(0);
|
||||
}
|
||||
|
||||
static void SIEconnect(void)
|
||||
{
|
||||
// Connect USB device
|
||||
uint8_t status = SIEgetDeviceStatus();
|
||||
SIEsetDeviceStatus(status | SIE_DS_CON);
|
||||
}
|
||||
|
||||
|
||||
static void SIEdisconnect(void)
|
||||
{
|
||||
// Disconnect USB device
|
||||
uint8_t status = SIEgetDeviceStatus();
|
||||
SIEsetDeviceStatus(status & ~SIE_DS_CON);
|
||||
}
|
||||
|
||||
|
||||
static uint8_t selectEndpointClearInterrupt(uint8_t endpoint)
|
||||
{
|
||||
// Implemented using using EP_INT_CLR.
|
||||
LPC_USB->USBEpIntClr = EP(endpoint);
|
||||
while (!(LPC_USB->USBDevIntSt & CDFULL));
|
||||
return (uint8_t)LPC_USB->USBCmdData;
|
||||
}
|
||||
|
||||
|
||||
static void enableEndpointEvent(uint8_t endpoint)
|
||||
{
|
||||
// Enable an endpoint interrupt
|
||||
LPC_USB->USBEpIntEn |= EP(endpoint);
|
||||
}
|
||||
|
||||
static void disableEndpointEvent(uint8_t endpoint) __attribute__((unused));
|
||||
static void disableEndpointEvent(uint8_t endpoint)
|
||||
{
|
||||
// Disable an endpoint interrupt
|
||||
LPC_USB->USBEpIntEn &= ~EP(endpoint);
|
||||
}
|
||||
|
||||
|
||||
static uint32_t endpointReadcore(uint8_t endpoint, uint8_t *buffer, uint32_t size)
|
||||
{
|
||||
// Read from an OUT endpoint
|
||||
uint32_t actual_size;
|
||||
uint32_t i;
|
||||
uint32_t data = 0;
|
||||
uint8_t offset;
|
||||
|
||||
LPC_USB->USBCtrl = LOG_ENDPOINT(endpoint) | RD_EN;
|
||||
while (!(LPC_USB->USBRxPLen & PKT_RDY));
|
||||
|
||||
actual_size = LPC_USB->USBRxPLen & PKT_LNGTH_MASK;
|
||||
|
||||
offset = 0;
|
||||
|
||||
if (actual_size > 0) {
|
||||
for (i = 0; i < actual_size; i++) {
|
||||
if (offset == 0) {
|
||||
// Fetch up to four bytes of data as a word
|
||||
data = LPC_USB->USBRxData;
|
||||
}
|
||||
|
||||
// extract a byte
|
||||
if (size) {
|
||||
*buffer = (data >> offset) & 0xff;
|
||||
buffer++;
|
||||
size--;
|
||||
}
|
||||
|
||||
// move on to the next byte
|
||||
offset = (offset + 8) % 32;
|
||||
}
|
||||
} else {
|
||||
(void)LPC_USB->USBRxData;
|
||||
}
|
||||
|
||||
LPC_USB->USBCtrl = 0;
|
||||
|
||||
return actual_size;
|
||||
}
|
||||
|
||||
static void endpointWritecore(uint8_t endpoint, uint8_t *buffer, uint32_t size)
|
||||
{
|
||||
// Write to an IN endpoint
|
||||
uint32_t temp, data;
|
||||
uint8_t offset;
|
||||
|
||||
LPC_USB->USBCtrl = LOG_ENDPOINT(endpoint) | WR_EN;
|
||||
|
||||
LPC_USB->USBTxPLen = size;
|
||||
offset = 0;
|
||||
data = 0;
|
||||
|
||||
if (size > 0) {
|
||||
do {
|
||||
// Fetch next data byte into a word-sized temporary variable
|
||||
temp = *buffer++;
|
||||
|
||||
// Add to current data word
|
||||
temp = temp << offset;
|
||||
data = data | temp;
|
||||
|
||||
// move on to the next byte
|
||||
offset = (offset + 8) % 32;
|
||||
size--;
|
||||
|
||||
if ((offset == 0) || (size == 0)) {
|
||||
// Write the word to the endpoint
|
||||
LPC_USB->USBTxData = data;
|
||||
data = 0;
|
||||
}
|
||||
} while (size > 0);
|
||||
} else {
|
||||
LPC_USB->USBTxData = 0;
|
||||
}
|
||||
|
||||
// Clear WR_EN to cover zero length packet case
|
||||
LPC_USB->USBCtrl = 0;
|
||||
|
||||
SIEselectEndpoint(endpoint);
|
||||
SIEvalidateBuffer();
|
||||
}
|
||||
|
||||
USBPhy *get_usb_phy()
|
||||
{
|
||||
static USBPhyHw usbphy;
|
||||
return &usbphy;
|
||||
}
|
||||
|
||||
USBPhyHw::USBPhyHw(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
USBPhyHw::~USBPhyHw(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void USBPhyHw::init(USBPhyEvents *events)
|
||||
{
|
||||
this->events = events;
|
||||
|
||||
// Disable IRQ
|
||||
NVIC_DisableIRQ(USB_IRQn);
|
||||
|
||||
// Enable power to USB device controller
|
||||
LPC_SC->PCONP |= PCUSB;
|
||||
|
||||
// Enable USB clocks
|
||||
LPC_USB->USBClkCtrl |= DEV_CLK_EN | AHB_CLK_EN;
|
||||
while (LPC_USB->USBClkSt != (DEV_CLK_ON | AHB_CLK_ON));
|
||||
|
||||
// Configure pins P0.29 and P0.30 to be USB D+ and USB D-
|
||||
LPC_PINCON->PINSEL1 &= 0xc3ffffff;
|
||||
LPC_PINCON->PINSEL1 |= 0x14000000;
|
||||
|
||||
// Disconnect USB device
|
||||
SIEdisconnect();
|
||||
|
||||
// Configure pin P2.9 to be Connect
|
||||
LPC_PINCON->PINSEL4 &= 0xfffcffff;
|
||||
LPC_PINCON->PINSEL4 |= 0x00040000;
|
||||
|
||||
// Connect must be low for at least 2.5uS
|
||||
wait(0.3);
|
||||
|
||||
// Set the maximum packet size for the control endpoints
|
||||
endpoint_add(EP0IN, MAX_PACKET_SIZE_EP0, USB_EP_TYPE_CTRL);
|
||||
endpoint_add(EP0OUT, MAX_PACKET_SIZE_EP0, USB_EP_TYPE_CTRL);
|
||||
|
||||
// Attach IRQ
|
||||
instance = this;
|
||||
NVIC_SetVector(USB_IRQn, (uint32_t)&_usbisr);
|
||||
|
||||
// Enable interrupts for device events and EP0
|
||||
LPC_USB->USBDevIntEn = EP_SLOW | DEV_STAT | FRAME;
|
||||
enableEndpointEvent(EP0IN);
|
||||
enableEndpointEvent(EP0OUT);
|
||||
}
|
||||
|
||||
void USBPhyHw::deinit()
|
||||
{
|
||||
// Ensure device disconnected
|
||||
SIEdisconnect();
|
||||
// Disable USB interrupts
|
||||
NVIC_DisableIRQ(USB_IRQn);
|
||||
events = NULL;
|
||||
}
|
||||
|
||||
bool USBPhyHw::powered()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void USBPhyHw::connect(void)
|
||||
{
|
||||
NVIC_EnableIRQ(USB_IRQn);
|
||||
// Connect USB device
|
||||
SIEconnect();
|
||||
}
|
||||
|
||||
void USBPhyHw::disconnect(void)
|
||||
{
|
||||
NVIC_DisableIRQ(USB_IRQn);
|
||||
// Disconnect USB device
|
||||
SIEdisconnect();
|
||||
}
|
||||
|
||||
void USBPhyHw::configure(void)
|
||||
{
|
||||
SIEconfigureDevice();
|
||||
}
|
||||
|
||||
void USBPhyHw::unconfigure(void)
|
||||
{
|
||||
SIEunconfigureDevice();
|
||||
}
|
||||
|
||||
void USBPhyHw::sof_enable()
|
||||
{
|
||||
//TODO
|
||||
}
|
||||
|
||||
void USBPhyHw::sof_disable()
|
||||
{
|
||||
//TODO
|
||||
}
|
||||
|
||||
void USBPhyHw::set_address(uint8_t address)
|
||||
{
|
||||
SIEsetAddress(address);
|
||||
}
|
||||
|
||||
uint32_t USBPhyHw::ep0_set_max_packet(uint32_t max_packet)
|
||||
{
|
||||
return MAX_PACKET_SIZE_EP0;
|
||||
}
|
||||
|
||||
void USBPhyHw::ep0_setup_read_result(uint8_t *buffer, uint32_t size)
|
||||
{
|
||||
endpointReadcore(EP0OUT, buffer, size);
|
||||
}
|
||||
|
||||
void USBPhyHw::ep0_read(void)
|
||||
{
|
||||
endpoint_read(EP0OUT, MAX_PACKET_SIZE_EP0);
|
||||
}
|
||||
|
||||
uint32_t USBPhyHw::ep0_read_result(uint8_t *buffer, uint32_t size)
|
||||
{
|
||||
return endpointReadcore(EP0OUT, buffer, size);
|
||||
}
|
||||
|
||||
void USBPhyHw::ep0_write(uint8_t *buffer, uint32_t size)
|
||||
{
|
||||
endpointWritecore(EP0IN, buffer, size);
|
||||
}
|
||||
|
||||
void USBPhyHw::ep0_stall(void)
|
||||
{
|
||||
// This will stall both control endpoints
|
||||
endpoint_stall(EP0OUT);
|
||||
}
|
||||
|
||||
bool USBPhyHw::endpoint_read(usb_ep_t endpoint, uint32_t maximumSize)
|
||||
{
|
||||
// Don't clear isochronous endpoints
|
||||
if ((DESC_TO_PHY(endpoint) >> 1) % 3 || (DESC_TO_PHY(endpoint) >> 1) == 0) {
|
||||
SIEselectEndpoint(endpoint);
|
||||
SIEclearBuffer();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool USBPhyHw::endpoint_read_result(usb_ep_t endpoint, uint8_t *buffer, uint32_t size, uint32_t *bytesRead)
|
||||
{
|
||||
|
||||
//for isochronous endpoint, we don't wait an interrupt
|
||||
if ((DESC_TO_PHY(endpoint) >> 1) % 3 || (DESC_TO_PHY(endpoint) >> 1) == 0) {
|
||||
if (!(epComplete & EP(endpoint))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
*bytesRead = endpointReadcore(endpoint, buffer, size);
|
||||
epComplete &= ~EP(endpoint);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool USBPhyHw::endpoint_write(usb_ep_t endpoint, uint8_t *data, uint32_t size)
|
||||
{
|
||||
epComplete &= ~EP(endpoint);
|
||||
|
||||
endpointWritecore(endpoint, data, size);
|
||||
return true;
|
||||
}
|
||||
|
||||
void USBPhyHw::endpoint_abort(usb_ep_t endpoint)
|
||||
{
|
||||
//TODO - needs to be implemented
|
||||
}
|
||||
|
||||
bool USBPhyHw::endpoint_add(usb_ep_t endpoint, uint32_t maxPacket, usb_ep_type_t type)
|
||||
{
|
||||
// Realise an endpoint
|
||||
LPC_USB->USBDevIntClr = EP_RLZED;
|
||||
LPC_USB->USBReEp |= EP(endpoint);
|
||||
LPC_USB->USBEpInd = DESC_TO_PHY(endpoint);
|
||||
LPC_USB->USBMaxPSize = maxPacket;
|
||||
|
||||
while (!(LPC_USB->USBDevIntSt & EP_RLZED));
|
||||
LPC_USB->USBDevIntClr = EP_RLZED;
|
||||
|
||||
enableEndpointEvent(endpoint);
|
||||
return true;
|
||||
}
|
||||
|
||||
void USBPhyHw::endpoint_remove(usb_ep_t endpoint)
|
||||
{
|
||||
// Unrealise an endpoint
|
||||
|
||||
disableEndpointEvent(endpoint);
|
||||
|
||||
LPC_USB->USBDevIntClr = EP_RLZED;
|
||||
LPC_USB->USBReEp &= ~EP(endpoint);
|
||||
|
||||
while (!(LPC_USB->USBDevIntSt & EP_RLZED));
|
||||
LPC_USB->USBDevIntClr = EP_RLZED;
|
||||
}
|
||||
|
||||
void USBPhyHw::endpoint_stall(usb_ep_t endpoint)
|
||||
{
|
||||
// Stall an endpoint
|
||||
if ((endpoint == EP0IN) || (endpoint == EP0OUT)) {
|
||||
// Conditionally stall both control endpoints
|
||||
SIEsetEndpointStatus(EP0OUT, SIE_SES_CND_ST);
|
||||
} else {
|
||||
SIEsetEndpointStatus(endpoint, SIE_SES_ST);
|
||||
}
|
||||
}
|
||||
|
||||
void USBPhyHw::endpoint_unstall(usb_ep_t endpoint)
|
||||
{
|
||||
// Unstall an endpoint. The endpoint will also be reinitialised
|
||||
SIEsetEndpointStatus(endpoint, 0);
|
||||
}
|
||||
|
||||
void USBPhyHw::remote_wakeup(void)
|
||||
{
|
||||
// Remote wakeup
|
||||
uint8_t status;
|
||||
|
||||
// Enable USB clocks
|
||||
LPC_USB->USBClkCtrl |= DEV_CLK_EN | AHB_CLK_EN;
|
||||
while (LPC_USB->USBClkSt != (DEV_CLK_ON | AHB_CLK_ON));
|
||||
|
||||
status = SIEgetDeviceStatus();
|
||||
SIEsetDeviceStatus(status & ~SIE_DS_SUS);
|
||||
}
|
||||
|
||||
const usb_ep_table_t *USBPhyHw::endpoint_table()
|
||||
{
|
||||
static const usb_ep_table_t lpc_table = {
|
||||
4096 - 32 * 4, // 32 words for endpoint buffers
|
||||
// +3 based added to interrupt and isochronous to ensure enough
|
||||
// space for 4 byte alignment
|
||||
{
|
||||
{USB_EP_ATTR_ALLOW_CTRL | USB_EP_ATTR_DIR_IN_AND_OUT, 1, 0},
|
||||
{USB_EP_ATTR_ALLOW_INT | USB_EP_ATTR_DIR_IN_AND_OUT, 1, 3},
|
||||
{USB_EP_ATTR_ALLOW_BULK | USB_EP_ATTR_DIR_IN_AND_OUT, 2, 0},
|
||||
{USB_EP_ATTR_ALLOW_ISO | USB_EP_ATTR_DIR_IN_AND_OUT, 1, 3},
|
||||
{USB_EP_ATTR_ALLOW_INT | USB_EP_ATTR_DIR_IN_AND_OUT, 1, 3},
|
||||
{USB_EP_ATTR_ALLOW_BULK | USB_EP_ATTR_DIR_IN_AND_OUT, 2, 0},
|
||||
{USB_EP_ATTR_ALLOW_ISO | USB_EP_ATTR_DIR_IN_AND_OUT, 1, 3},
|
||||
{USB_EP_ATTR_ALLOW_INT | USB_EP_ATTR_DIR_IN_AND_OUT, 1, 3},
|
||||
{USB_EP_ATTR_ALLOW_BULK | USB_EP_ATTR_DIR_IN_AND_OUT, 2, 0},
|
||||
{USB_EP_ATTR_ALLOW_ISO | USB_EP_ATTR_DIR_IN_AND_OUT, 1, 3},
|
||||
{USB_EP_ATTR_ALLOW_INT | USB_EP_ATTR_DIR_IN_AND_OUT, 1, 3},
|
||||
{USB_EP_ATTR_ALLOW_BULK | USB_EP_ATTR_DIR_IN_AND_OUT, 2, 0},
|
||||
{USB_EP_ATTR_ALLOW_ISO | USB_EP_ATTR_DIR_IN_AND_OUT, 1, 3},
|
||||
{USB_EP_ATTR_ALLOW_INT | USB_EP_ATTR_DIR_IN_AND_OUT, 1, 3},
|
||||
{USB_EP_ATTR_ALLOW_BULK | USB_EP_ATTR_DIR_IN_AND_OUT, 2, 0},
|
||||
{USB_EP_ATTR_ALLOW_BULK | USB_EP_ATTR_DIR_IN_AND_OUT, 2, 0}
|
||||
}
|
||||
};
|
||||
return &lpc_table;
|
||||
}
|
||||
|
||||
void USBPhyHw::_usbisr(void)
|
||||
{
|
||||
NVIC_DisableIRQ(USB_IRQn);
|
||||
instance->events->start_process();
|
||||
}
|
||||
|
||||
void USBPhyHw::process(void)
|
||||
{
|
||||
uint8_t devStat;
|
||||
|
||||
if (LPC_USB->USBDevIntSt & FRAME) {
|
||||
// Start of frame event
|
||||
events->sof(SIEgetFrameNumber());
|
||||
// Clear interrupt status flag
|
||||
LPC_USB->USBDevIntClr = FRAME;
|
||||
}
|
||||
|
||||
if (LPC_USB->USBDevIntSt & DEV_STAT) {
|
||||
// Device Status interrupt
|
||||
// Must clear the interrupt status flag before reading the device status from the SIE
|
||||
LPC_USB->USBDevIntClr = DEV_STAT;
|
||||
|
||||
// Read device status from SIE
|
||||
devStat = SIEgetDeviceStatus();
|
||||
//printf("devStat: %d\r\n", devStat);
|
||||
|
||||
if (devStat & SIE_DS_SUS_CH) {
|
||||
// Suspend status changed
|
||||
if ((devStat & SIE_DS_SUS) != 0) {
|
||||
events->suspend(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (devStat & SIE_DS_RST) {
|
||||
// Bus reset
|
||||
if ((devStat & SIE_DS_SUS) == 0) {
|
||||
events->suspend(true);
|
||||
}
|
||||
events->reset();
|
||||
}
|
||||
}
|
||||
|
||||
if (LPC_USB->USBDevIntSt & EP_SLOW) {
|
||||
// (Slow) Endpoint Interrupt
|
||||
|
||||
// Process IN packets before SETUP packets
|
||||
// Note - order of OUT and SETUP does not matter as OUT packets
|
||||
// are clobbered by SETUP packets and thus ignored.
|
||||
//
|
||||
// A SETUP packet can arrive at any time where as an IN packet is
|
||||
// only sent after calling EP0write and an OUT packet after EP0read.
|
||||
// The functions EP0write and EP0read are called only in response to
|
||||
// a setup packet or IN/OUT packets sent in response to that
|
||||
// setup packet. Therefore, if an IN or OUT packet is pending
|
||||
// at the same time as a SETUP packet, the IN or OUT packet belongs
|
||||
// to the previous control transfer and should either be processed
|
||||
// before the SETUP packet (in the case of IN) or dropped (in the
|
||||
// case of OUT as SETUP clobbers the OUT data).
|
||||
if (LPC_USB->USBEpIntSt & EP(EP0IN)) {
|
||||
selectEndpointClearInterrupt(EP0IN);
|
||||
LPC_USB->USBDevIntClr = EP_SLOW;
|
||||
events->ep0_in();
|
||||
}
|
||||
|
||||
// Process each endpoint interrupt
|
||||
if (LPC_USB->USBEpIntSt & EP(EP0OUT)) {
|
||||
if (selectEndpointClearInterrupt(EP0OUT) & SIE_SE_STP) {
|
||||
// this is a setup packet
|
||||
events->ep0_setup();
|
||||
} else {
|
||||
events->ep0_out();
|
||||
}
|
||||
LPC_USB->USBDevIntClr = EP_SLOW;
|
||||
}
|
||||
|
||||
//TODO - should probably process in the reverse order
|
||||
for (uint8_t num = 2; num < 16 * 2; num++) {
|
||||
uint8_t endpoint = PHY_TO_DESC(num);
|
||||
if (LPC_USB->USBEpIntSt & EP(endpoint)) {
|
||||
selectEndpointClearInterrupt(endpoint);
|
||||
epComplete |= EP(endpoint);
|
||||
LPC_USB->USBDevIntClr = EP_SLOW;
|
||||
if (endpoint & 0x80) {//TODO - use macro
|
||||
events->in(endpoint);
|
||||
} else {
|
||||
events->out(endpoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NVIC_ClearPendingIRQ(USB_IRQn);
|
||||
NVIC_EnableIRQ(USB_IRQn);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,66 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2018-2018 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef USBPHYHW_H
|
||||
#define USBPHYHW_H
|
||||
|
||||
#include "mbed.h"
|
||||
#include "USBPhy.h"
|
||||
|
||||
|
||||
class USBPhyHw : public USBPhy {
|
||||
public:
|
||||
USBPhyHw();
|
||||
virtual ~USBPhyHw();
|
||||
virtual void init(USBPhyEvents *events);
|
||||
virtual void deinit();
|
||||
virtual bool powered();
|
||||
virtual void connect();
|
||||
virtual void disconnect();
|
||||
virtual void configure();
|
||||
virtual void unconfigure();
|
||||
virtual void sof_enable();
|
||||
virtual void sof_disable();
|
||||
virtual void set_address(uint8_t address);
|
||||
virtual void remote_wakeup();
|
||||
virtual const usb_ep_table_t *endpoint_table();
|
||||
|
||||
virtual uint32_t ep0_set_max_packet(uint32_t max_packet);
|
||||
virtual void ep0_setup_read_result(uint8_t *buffer, uint32_t size);
|
||||
virtual void ep0_read(void);
|
||||
virtual uint32_t ep0_read_result(uint8_t *buffer, uint32_t size);
|
||||
virtual void ep0_write(uint8_t *buffer, uint32_t size);
|
||||
virtual void ep0_stall(void);
|
||||
|
||||
virtual bool endpoint_add(usb_ep_t endpoint, uint32_t max_packet, usb_ep_type_t type);
|
||||
virtual void endpoint_remove(usb_ep_t endpoint);
|
||||
virtual void endpoint_stall(usb_ep_t endpoint);
|
||||
virtual void endpoint_unstall(usb_ep_t endpoint);
|
||||
|
||||
virtual bool endpoint_read(usb_ep_t endpoint, uint32_t maximumSize);
|
||||
virtual bool endpoint_read_result(usb_ep_t endpoint, uint8_t *data, uint32_t size, uint32_t *bytesRead);
|
||||
virtual bool endpoint_write(usb_ep_t endpoint, uint8_t *data, uint32_t size);
|
||||
virtual void endpoint_abort(usb_ep_t endpoint);
|
||||
|
||||
virtual void process();
|
||||
|
||||
private:
|
||||
USBPhyEvents *events;
|
||||
|
||||
static void _usbisr(void);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -232,7 +232,7 @@
|
|||
"extra_labels": ["NXP", "LPC176X", "MBED_LPC1768"],
|
||||
"supported_toolchains": ["ARM", "uARM", "GCC_ARM", "GCC_CR", "IAR"],
|
||||
"detect_code": ["1010"],
|
||||
"device_has": ["ANALOGIN", "ANALOGOUT", "CAN", "DEBUG_AWARENESS", "ETHERNET", "I2C", "I2CSLAVE", "INTERRUPTIN", "LOCALFILESYSTEM", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SEMIHOST", "SERIAL", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES", "FLASH"],
|
||||
"device_has": ["ANALOGIN", "ANALOGOUT", "CAN", "DEBUG_AWARENESS", "ETHERNET", "I2C", "I2CSLAVE", "INTERRUPTIN", "LOCALFILESYSTEM", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SEMIHOST", "SERIAL", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES", "FLASH", "USBDEVICE"],
|
||||
"release_versions": ["2", "5"],
|
||||
"features": ["LWIP"],
|
||||
"device_name": "LPC1768",
|
||||
|
|
Loading…
Reference in New Issue