975 lines
30 KiB
C
975 lines
30 KiB
C
|
|
/* -----------------------------------------------------------------------------
|
||
|
|
* Copyright (c) 2013-2017 ARM Ltd.
|
||
|
|
*
|
||
|
|
* This software is provided 'as-is', without any express or implied warranty.
|
||
|
|
* In no event will the authors be held liable for any damages arising from
|
||
|
|
* the use of this software. Permission is granted to anyone to use this
|
||
|
|
* software for any purpose, including commercial applications, and to alter
|
||
|
|
* it and redistribute it freely, subject to the following restrictions:
|
||
|
|
*
|
||
|
|
* 1. The origin of this software must not be misrepresented; you must not
|
||
|
|
* claim that you wrote the original software. If you use this software in
|
||
|
|
* a product, an acknowledgment in the product documentation would be
|
||
|
|
* appreciated but is not required.
|
||
|
|
*
|
||
|
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
||
|
|
* misrepresented as being the original software.
|
||
|
|
*
|
||
|
|
* 3. This notice may not be removed or altered from any source distribution.
|
||
|
|
*
|
||
|
|
*
|
||
|
|
* $Date: 19. September 2017
|
||
|
|
* $Revision: V2.1
|
||
|
|
*
|
||
|
|
* Driver: Driver_USBD0
|
||
|
|
* Configured: via RTE_Device.h configuration file
|
||
|
|
* Project: USB Full/Low-Speed Device Driver for ST STM32F10x
|
||
|
|
* ----------------------------------------------------------------------
|
||
|
|
* Use the following configuration settings in the middleware component
|
||
|
|
* to connect to this driver.
|
||
|
|
*
|
||
|
|
* Configuration Setting Value
|
||
|
|
* --------------------- -----
|
||
|
|
* Connect to hardware via Driver_USBD# = 0
|
||
|
|
* -------------------------------------------------------------------- */
|
||
|
|
|
||
|
|
/* History:
|
||
|
|
* Version 2.1
|
||
|
|
* Added support for CMSIS-RTOS2
|
||
|
|
* Version 2.0
|
||
|
|
* Updated to CMSIS Driver API V2.01
|
||
|
|
* Version 1.00
|
||
|
|
* Initial release
|
||
|
|
*/
|
||
|
|
|
||
|
|
#include <stdint.h>
|
||
|
|
#include <string.h>
|
||
|
|
|
||
|
|
#include "RTE_Components.h"
|
||
|
|
|
||
|
|
#if defined(RTE_CMSIS_RTOS2)
|
||
|
|
#include "cmsis_os2.h"
|
||
|
|
#elif defined(RTE_CMSIS_RTOS)
|
||
|
|
#include "cmsis_os.h"
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#include "stm32f10x.h"
|
||
|
|
|
||
|
|
#include "GPIO_STM32F10x.h"
|
||
|
|
#include "USBD_STM32F10x.h"
|
||
|
|
|
||
|
|
#include "Driver_USBD.h"
|
||
|
|
|
||
|
|
#include "RTE_Device.h"
|
||
|
|
#include "RTE_Components.h"
|
||
|
|
|
||
|
|
// Do basic RTE configuration check
|
||
|
|
#if (RTE_USB_DEVICE == 0)
|
||
|
|
#error Enable USB Device in RTE_Device.h!
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#ifndef USBD_MAX_ENDPOINT_NUM
|
||
|
|
#define USBD_MAX_ENDPOINT_NUM 8U
|
||
|
|
#endif
|
||
|
|
#if (USBD_MAX_ENDPOINT_NUM > 8)
|
||
|
|
#error Too many Endpoints, maximum IN/OUT Endpoint pairs that this driver supports is 8 !!!
|
||
|
|
#endif
|
||
|
|
|
||
|
|
// Endpoint buffer address
|
||
|
|
|
||
|
|
// Endpoint buffer sizes in bytes
|
||
|
|
// (total available memory for Endpoint buffers is 512 Bytes - EP_BUF_ADDR)
|
||
|
|
#ifndef USB_EP0_RX_BUF_SIZE
|
||
|
|
#define USB_EP0_RX_BUF_SIZE 8U
|
||
|
|
#endif
|
||
|
|
#define USB_EP0_RX_BUF_OFFSET 0x80U
|
||
|
|
|
||
|
|
#ifndef USB_EP0_TX_BUF_SIZE
|
||
|
|
#define USB_EP0_TX_BUF_SIZE 8U
|
||
|
|
#endif
|
||
|
|
#define USB_EP0_TX_BUF_OFFSET USB_EP0_RX_BUF_OFFSET + USB_EP0_RX_BUF_SIZE
|
||
|
|
|
||
|
|
#ifndef USB_EP1_RX_BUF_SIZE
|
||
|
|
#define USB_EP1_RX_BUF_SIZE 64U
|
||
|
|
#endif
|
||
|
|
#define USB_EP1_RX_BUF_OFFSET USB_EP0_TX_BUF_OFFSET + USB_EP0_TX_BUF_SIZE
|
||
|
|
|
||
|
|
#ifndef USB_EP1_TX_BUF_SIZE
|
||
|
|
#define USB_EP1_TX_BUF_SIZE 64U
|
||
|
|
#endif
|
||
|
|
#define USB_EP1_TX_BUF_OFFSET USB_EP1_RX_BUF_OFFSET + USB_EP1_RX_BUF_SIZE
|
||
|
|
|
||
|
|
#ifndef USB_EP2_RX_BUF_SIZE
|
||
|
|
#define USB_EP2_RX_BUF_SIZE 64U
|
||
|
|
#endif
|
||
|
|
#define USB_EP2_RX_BUF_OFFSET USB_EP1_TX_BUF_OFFSET + USB_EP1_TX_BUF_SIZE
|
||
|
|
|
||
|
|
#ifndef USB_EP2_TX_BUF_SIZE
|
||
|
|
#define USB_EP2_TX_BUF_SIZE 64U
|
||
|
|
#endif
|
||
|
|
#define USB_EP2_TX_BUF_OFFSET USB_EP2_RX_BUF_OFFSET + USB_EP2_RX_BUF_SIZE
|
||
|
|
|
||
|
|
#ifndef USB_EP3_RX_BUF_SIZE
|
||
|
|
#define USB_EP3_RX_BUF_SIZE 8U
|
||
|
|
#endif
|
||
|
|
#define USB_EP3_RX_BUF_OFFSET USB_EP2_TX_BUF_OFFSET + USB_EP2_TX_BUF_SIZE
|
||
|
|
|
||
|
|
#ifndef USB_EP3_TX_BUF_SIZE
|
||
|
|
#define USB_EP3_TX_BUF_SIZE 8U
|
||
|
|
#endif
|
||
|
|
#define USB_EP3_TX_BUF_OFFSET USB_EP3_RX_BUF_OFFSET + USB_EP3_RX_BUF_SIZE
|
||
|
|
|
||
|
|
#ifndef USB_EP4_RX_BUF_SIZE
|
||
|
|
#define USB_EP4_RX_BUF_SIZE 8U
|
||
|
|
#endif
|
||
|
|
#define USB_EP4_RX_BUF_OFFSET USB_EP3_TX_BUF_OFFSET + USB_EP3_TX_BUF_SIZE
|
||
|
|
|
||
|
|
#ifndef USB_EP4_TX_BUF_SIZE
|
||
|
|
#define USB_EP4_TX_BUF_SIZE 8U
|
||
|
|
#endif
|
||
|
|
#define USB_EP4_TX_BUF_OFFSET USB_EP4_RX_BUF_OFFSET + USB_EP4_RX_BUF_SIZE
|
||
|
|
|
||
|
|
#ifndef USB_EP5_RX_BUF_SIZE
|
||
|
|
#define USB_EP5_RX_BUF_SIZE 8U
|
||
|
|
#endif
|
||
|
|
#define USB_EP5_RX_BUF_OFFSET USB_EP4_TX_BUF_OFFSET + USB_EP4_TX_BUF_SIZE
|
||
|
|
|
||
|
|
#ifndef USB_EP5_TX_BUF_SIZE
|
||
|
|
#define USB_EP5_TX_BUF_SIZE 8U
|
||
|
|
#endif
|
||
|
|
#define USB_EP5_TX_BUF_OFFSET USB_EP5_RX_BUF_OFFSET + USB_EP5_RX_BUF_SIZE
|
||
|
|
|
||
|
|
#ifndef USB_EP6_RX_BUF_SIZE
|
||
|
|
#define USB_EP6_RX_BUF_SIZE 8U
|
||
|
|
#endif
|
||
|
|
#define USB_EP6_RX_BUF_OFFSET USB_EP5_TX_BUF_OFFSET + USB_EP5_TX_BUF_SIZE
|
||
|
|
|
||
|
|
#ifndef USB_EP6_TX_BUF_SIZE
|
||
|
|
#define USB_EP6_TX_BUF_SIZE 8U
|
||
|
|
#endif
|
||
|
|
#define USB_EP6_TX_BUF_OFFSET USB_EP6_RX_BUF_OFFSET + USB_EP6_RX_BUF_SIZE
|
||
|
|
|
||
|
|
#ifndef USB_EP7_RX_BUF_SIZE
|
||
|
|
#define USB_EP7_RX_BUF_SIZE 8U
|
||
|
|
#endif
|
||
|
|
#define USB_EP7_RX_BUF_OFFSET USB_EP6_TX_BUF_OFFSET + USB_EP6_TX_BUF_SIZE
|
||
|
|
|
||
|
|
#ifndef USB_EP7_TX_BUF_SIZE
|
||
|
|
#define USB_EP7_TX_BUF_SIZE 8U
|
||
|
|
#endif
|
||
|
|
#define USB_EP7_TX_BUF_OFFSET USB_EP7_RX_BUF_OFFSET + USB_EP7_RX_BUF_SIZE
|
||
|
|
|
||
|
|
#if ((USB_EP7_TX_BUF_OFFSET + USB_EP7_TX_BUF_SIZE) > 512U)
|
||
|
|
#error "The SUM of all Endpoint buffers sizes exceeds available dedicated RAM size (512 Bytes)."
|
||
|
|
#endif
|
||
|
|
|
||
|
|
|
||
|
|
// USBD Driver *****************************************************************
|
||
|
|
|
||
|
|
#define ARM_USBD_DRV_VERSION ARM_DRIVER_VERSION_MAJOR_MINOR(2,1)
|
||
|
|
|
||
|
|
// Driver Version
|
||
|
|
static const ARM_DRIVER_VERSION usbd_driver_version = { ARM_USBD_API_VERSION, ARM_USBD_DRV_VERSION };
|
||
|
|
|
||
|
|
// Driver Capabilities
|
||
|
|
static const ARM_USBD_CAPABILITIES usbd_driver_capabilities = {
|
||
|
|
0U, // VBUS Detection
|
||
|
|
0U, // Event VBUS On
|
||
|
|
0U // Event VBUS Off
|
||
|
|
};
|
||
|
|
|
||
|
|
#define EP_NUM(ep_addr) ((ep_addr) & ARM_USB_ENDPOINT_NUMBER_MASK)
|
||
|
|
#define EP_ID(ep_addr) ((EP_NUM(ep_addr) * 2U) + (((ep_addr) >> 7) & 1U))
|
||
|
|
|
||
|
|
typedef struct { // Endpoint structure definition
|
||
|
|
uint8_t *data;
|
||
|
|
uint32_t num;
|
||
|
|
uint32_t num_transferred_total;
|
||
|
|
uint16_t num_transferring;
|
||
|
|
uint16_t max_packet_size;
|
||
|
|
uint8_t active;
|
||
|
|
} ENDPOINT_t;
|
||
|
|
|
||
|
|
static ARM_USBD_SignalDeviceEvent_t SignalDeviceEvent;
|
||
|
|
static ARM_USBD_SignalEndpointEvent_t SignalEndpointEvent;
|
||
|
|
|
||
|
|
static bool hw_powered = false;
|
||
|
|
static bool hw_initialized = false;
|
||
|
|
static ARM_USBD_STATE usbd_state;
|
||
|
|
static uint8_t setup_packet[8]; // Setup packet data
|
||
|
|
static volatile uint8_t setup_received; // Setup packet received
|
||
|
|
|
||
|
|
// Endpoint buffer address
|
||
|
|
#define EP_BUF_ADDR (sizeof(EP_BUF_DSCR)*8)
|
||
|
|
// Pointer to Endpoint descriptor table
|
||
|
|
static EP_BUF_DSCR *pBUF_DSCR = (EP_BUF_DSCR *)USB_PMA_ADDR;
|
||
|
|
|
||
|
|
static const uint16_t EP_buff_offset[16] = { USB_EP0_RX_BUF_OFFSET, USB_EP0_TX_BUF_OFFSET,
|
||
|
|
USB_EP1_RX_BUF_OFFSET, USB_EP1_TX_BUF_OFFSET,
|
||
|
|
USB_EP2_RX_BUF_OFFSET, USB_EP2_TX_BUF_OFFSET,
|
||
|
|
USB_EP3_RX_BUF_OFFSET, USB_EP3_TX_BUF_OFFSET,
|
||
|
|
USB_EP4_RX_BUF_OFFSET, USB_EP4_TX_BUF_OFFSET,
|
||
|
|
USB_EP5_RX_BUF_OFFSET, USB_EP5_TX_BUF_OFFSET,
|
||
|
|
USB_EP6_RX_BUF_OFFSET, USB_EP6_TX_BUF_OFFSET,
|
||
|
|
USB_EP7_RX_BUF_OFFSET, USB_EP7_TX_BUF_OFFSET };
|
||
|
|
|
||
|
|
// Endpoints runtime information
|
||
|
|
static volatile ENDPOINT_t ep[(USBD_MAX_ENDPOINT_NUM + 1U) * 2U];
|
||
|
|
|
||
|
|
#define IN_EP_RESET(num) (EPxREG(EP_NUM(num)) = (EPxREG(EP_NUM(num)) & (EP_MASK | EP_STAT_TX | EP_DTOG_TX)) | EP_CTR_TX | EP_CTR_RX)
|
||
|
|
#define OUT_EP_RESET(num) (EPxREG(EP_NUM(num)) = (EPxREG(EP_NUM(num)) & (EP_MASK | EP_STAT_RX | EP_DTOG_RX)) | EP_CTR_TX | EP_CTR_RX)
|
||
|
|
|
||
|
|
// Auxiliary functions
|
||
|
|
/**
|
||
|
|
\fn static void IN_EP_Status (uint8_t ep_num, uint32_t stat)
|
||
|
|
\brief Called to update Endpoint status
|
||
|
|
*/
|
||
|
|
void IN_EP_Status (uint8_t ep_num, uint32_t stat) {
|
||
|
|
uint32_t num, val, ep_reg;
|
||
|
|
|
||
|
|
num = ep_num & ARM_USB_ENDPOINT_NUMBER_MASK;
|
||
|
|
stat &= EP_STAT_TX;
|
||
|
|
ep_reg = EPxREG(num);
|
||
|
|
val = (ep_reg & EP_STAT_TX) ^ stat;
|
||
|
|
val = (ep_reg & ~EP_STAT_TX) | val;
|
||
|
|
EPxREG(num) = (val & (EP_MASK | EP_STAT_TX)) | EP_CTR_TX | EP_CTR_RX;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
\fn static void OUT_EP_Status (uint8_t ep_num, uint32_t stat)
|
||
|
|
\brief Called to update Endpoint status
|
||
|
|
*/
|
||
|
|
void OUT_EP_Status (uint8_t ep_num, uint32_t stat) {
|
||
|
|
uint32_t num, val, ep_reg;
|
||
|
|
|
||
|
|
num = ep_num & ARM_USB_ENDPOINT_NUMBER_MASK;
|
||
|
|
stat &= EP_STAT_RX;
|
||
|
|
ep_reg = EPxREG(num);
|
||
|
|
val = (ep_reg & EP_STAT_RX) ^ stat;
|
||
|
|
val = (ep_reg & ~EP_STAT_RX) | val;
|
||
|
|
EPxREG(num) = (val & (EP_MASK | EP_STAT_RX)) | EP_CTR_TX | EP_CTR_RX;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
\fn void USBD_EP_HW_Read (uint8_t ep_addr)
|
||
|
|
\brief Read data from USB Endpoint.
|
||
|
|
\param[in] ep_addr Endpoint Address
|
||
|
|
- ep_addr.0..3: Address
|
||
|
|
- ep_addr.7: Direction
|
||
|
|
\return number of data bytes read
|
||
|
|
*/
|
||
|
|
static void USBD_EP_HW_Read (uint8_t ep_addr) {
|
||
|
|
volatile ENDPOINT_t *ptr_ep;
|
||
|
|
uint32_t cnt, i;
|
||
|
|
__packed uint8_t *ptr_dest_8;
|
||
|
|
__packed uint16_t *ptr_dest;
|
||
|
|
volatile uint32_t *ptr_src;
|
||
|
|
uint8_t ep_num;
|
||
|
|
uint8_t tmp_buf[4];
|
||
|
|
|
||
|
|
ptr_ep = &ep[EP_ID(ep_addr)];
|
||
|
|
ep_num = EP_NUM(ep_addr);
|
||
|
|
|
||
|
|
cnt = (pBUF_DSCR + ep_num)->COUNT_RX & EP_COUNT_MASK;
|
||
|
|
|
||
|
|
// Check for ZLP
|
||
|
|
if (cnt == 0U) { return; }
|
||
|
|
|
||
|
|
// Check if buffer available
|
||
|
|
if (ptr_ep->data == 0U) { return; }
|
||
|
|
|
||
|
|
// Copy data from FIFO
|
||
|
|
ptr_src = (uint32_t *)(USB_PMA_ADDR + 2*((pBUF_DSCR + ep_num)->ADDR_RX));
|
||
|
|
ptr_dest = (__packed uint16_t *)(ptr_ep->data + ptr_ep->num_transferred_total);
|
||
|
|
|
||
|
|
i = cnt / 2U;
|
||
|
|
while (i != 0U) {
|
||
|
|
*ptr_dest++ = *ptr_src++;
|
||
|
|
i--;
|
||
|
|
}
|
||
|
|
ptr_ep->num_transferred_total += cnt;
|
||
|
|
|
||
|
|
// If data size is not equal n*2
|
||
|
|
if ((cnt & 1U) != 0U) {
|
||
|
|
ptr_dest_8 = (uint8_t *)(ptr_dest);
|
||
|
|
*((__packed uint16_t *)tmp_buf) = *ptr_src;
|
||
|
|
*ptr_dest_8 = tmp_buf[0];
|
||
|
|
}
|
||
|
|
|
||
|
|
if (cnt != ptr_ep->max_packet_size) { ptr_ep->num = 0U; }
|
||
|
|
else { ptr_ep->num -= cnt; }
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
\fn void USBD_EP_HW_Write (uint8_t ep_addr)
|
||
|
|
\brief Write data to Endpoint Buffer.
|
||
|
|
\param[in] ep_addr Endpoint Address
|
||
|
|
- ep_addr.0..7: Address
|
||
|
|
- ep_addr.7: Direction
|
||
|
|
*/
|
||
|
|
static void USBD_EP_HW_Write (uint8_t ep_addr) {
|
||
|
|
volatile ENDPOINT_t *ptr_ep;
|
||
|
|
uint8_t ep_num;
|
||
|
|
uint16_t num, i;
|
||
|
|
volatile uint32_t *ptr_dest;
|
||
|
|
__packed uint16_t *ptr_src;
|
||
|
|
|
||
|
|
ptr_ep = &ep[EP_ID(ep_addr)];
|
||
|
|
ep_num = EP_NUM(ep_addr);
|
||
|
|
|
||
|
|
if (ptr_ep->num > ptr_ep->max_packet_size) { num = ptr_ep->max_packet_size; }
|
||
|
|
else { num = ptr_ep->num; }
|
||
|
|
|
||
|
|
ptr_src = (__packed uint16_t *)(ptr_ep->data + ptr_ep->num_transferred_total);
|
||
|
|
ptr_dest = (uint32_t *)(USB_PMA_ADDR + 2*((pBUF_DSCR + ep_num)->ADDR_TX));
|
||
|
|
|
||
|
|
ptr_ep->num_transferring = num;
|
||
|
|
ptr_ep->num -= num;
|
||
|
|
|
||
|
|
// Copy data to EP Buffer
|
||
|
|
i = (num + 1U) >> 1;
|
||
|
|
while (i != 0U) {
|
||
|
|
*ptr_dest++ = *ptr_src++;
|
||
|
|
i--;
|
||
|
|
}
|
||
|
|
|
||
|
|
(pBUF_DSCR + ep_num)->COUNT_TX = num;
|
||
|
|
|
||
|
|
if ((EPxREG(ep_num) & EP_STAT_TX) != EP_TX_STALL) {
|
||
|
|
IN_EP_Status(ep_addr, EP_TX_VALID); // do not make EP valid if stalled
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/**
|
||
|
|
\fn static void USBD_Reset (uint8_t ep_addr)
|
||
|
|
\brief Called after usbd reset interrupt to reset configuration
|
||
|
|
*/
|
||
|
|
static void USBD_Reset (void) {
|
||
|
|
|
||
|
|
ISTR = 0; // Clear Interrupt Status
|
||
|
|
|
||
|
|
CNTR = CNTR_CTRM | CNTR_RESETM | CNTR_SUSPM | CNTR_WKUPM | CNTR_ERRM | CNTR_PMAOVRM;
|
||
|
|
|
||
|
|
|
||
|
|
// Reset global variables
|
||
|
|
setup_received = 0U;
|
||
|
|
memset((void *)USB_PMA_ADDR, 0, EP_BUF_ADDR);
|
||
|
|
memset((void *)&usbd_state, 0, sizeof(usbd_state));
|
||
|
|
memset((void *)ep, 0, sizeof(ep));
|
||
|
|
|
||
|
|
BTABLE = 0x00; // set BTABLE Address
|
||
|
|
|
||
|
|
DADDR = DADDR_EF | 0; // Enable USB Default Address
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
// USBD Driver functions
|
||
|
|
|
||
|
|
/**
|
||
|
|
\fn ARM_DRIVER_VERSION USBD_GetVersion (void)
|
||
|
|
\brief Get driver version.
|
||
|
|
\return \ref ARM_DRIVER_VERSION
|
||
|
|
*/
|
||
|
|
static ARM_DRIVER_VERSION USBD_GetVersion (void) { return usbd_driver_version; }
|
||
|
|
|
||
|
|
/**
|
||
|
|
\fn ARM_USBD_CAPABILITIES USBD_GetCapabilities (void)
|
||
|
|
\brief Get driver capabilities.
|
||
|
|
\return \ref ARM_USBD_CAPABILITIES
|
||
|
|
*/
|
||
|
|
static ARM_USBD_CAPABILITIES USBD_GetCapabilities (void) { return usbd_driver_capabilities; }
|
||
|
|
|
||
|
|
/**
|
||
|
|
\fn int32_t USBD_Initialize (ARM_USBD_SignalDeviceEvent_t cb_device_event,
|
||
|
|
ARM_USBD_SignalEndpointEvent_t cb_endpoint_event)
|
||
|
|
\brief Initialize USB Device Interface.
|
||
|
|
\param[in] cb_device_event Pointer to \ref ARM_USBD_SignalDeviceEvent
|
||
|
|
\param[in] cb_endpoint_event Pointer to \ref ARM_USBD_SignalEndpointEvent
|
||
|
|
\return \ref execution_status
|
||
|
|
*/
|
||
|
|
static int32_t USBD_Initialize (ARM_USBD_SignalDeviceEvent_t cb_device_event,
|
||
|
|
ARM_USBD_SignalEndpointEvent_t cb_endpoint_event) {
|
||
|
|
|
||
|
|
if (hw_initialized == true) {
|
||
|
|
return ARM_DRIVER_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
SignalDeviceEvent = cb_device_event;
|
||
|
|
SignalEndpointEvent = cb_endpoint_event;
|
||
|
|
|
||
|
|
#if (RTE_USB_DEVICE_CON_PIN)
|
||
|
|
// Configure CON pin (controls pull-up on D+ line)
|
||
|
|
GPIO_PortClock (RTE_USB_DEVICE_CON_PORT, true);
|
||
|
|
GPIO_PinWrite (RTE_USB_DEVICE_CON_PORT, RTE_USB_DEVICE_CON_BIT, !RTE_USB_DEVICE_CON_ACTIVE);
|
||
|
|
if (!GPIO_PinConfigure(RTE_USB_DEVICE_CON_PORT, RTE_USB_DEVICE_CON_BIT, GPIO_OUT_OPENDRAIN, GPIO_MODE_OUT10MHZ)) { return ARM_DRIVER_ERROR; }
|
||
|
|
#endif
|
||
|
|
|
||
|
|
hw_initialized = true;
|
||
|
|
|
||
|
|
return ARM_DRIVER_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
\fn int32_t USBD_Uninitialize (void)
|
||
|
|
\brief De-initialize USB Device Interface.
|
||
|
|
\return \ref execution_status
|
||
|
|
*/
|
||
|
|
static int32_t USBD_Uninitialize (void) {
|
||
|
|
|
||
|
|
#if (RTE_USB_DEVICE_CON_PIN)
|
||
|
|
// Unconfigure CON pin (controls pull-up on D+ line)
|
||
|
|
GPIO_PortClock (RTE_USB_DEVICE_CON_PORT, true);
|
||
|
|
GPIO_PinWrite (RTE_USB_DEVICE_CON_PORT, RTE_USB_DEVICE_CON_BIT, !RTE_USB_DEVICE_CON_ACTIVE);
|
||
|
|
if (!GPIO_PinConfigure(RTE_USB_DEVICE_CON_PORT, RTE_USB_DEVICE_CON_BIT, GPIO_IN_FLOATING, GPIO_MODE_INPUT)) { return ARM_DRIVER_ERROR; }
|
||
|
|
#endif
|
||
|
|
|
||
|
|
hw_initialized = false;
|
||
|
|
|
||
|
|
return ARM_DRIVER_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
\fn int32_t USBD_PowerControl (ARM_POWER_STATE state)
|
||
|
|
\brief Control USB Device Interface Power.
|
||
|
|
\param[in] state Power state
|
||
|
|
\return \ref execution_status
|
||
|
|
*/
|
||
|
|
static int32_t USBD_PowerControl (ARM_POWER_STATE state) {
|
||
|
|
|
||
|
|
switch (state) {
|
||
|
|
case ARM_POWER_OFF:
|
||
|
|
RCC->APB1ENR |= RCC_APB1ENR_USBEN; // Enable USB Device clock
|
||
|
|
NVIC_DisableIRQ (USB_LP_CAN1_RX0_IRQn); // Disable interrupt
|
||
|
|
NVIC_ClearPendingIRQ (USB_LP_CAN1_RX0_IRQn); // Clear pending interrupt
|
||
|
|
|
||
|
|
hw_powered = false; // Clear powered flag
|
||
|
|
CNTR = CNTR_FRES | CNTR_PDWN; // Switch off USB Device
|
||
|
|
#if (RTE_USB_DEVICE_CON_PIN)
|
||
|
|
if (!GPIO_PinConfigure(RTE_USB_DEVICE_CON_PORT, RTE_USB_DEVICE_CON_BIT, GPIO_IN_FLOATING, GPIO_MODE_INPUT)) { return ARM_DRIVER_ERROR; }
|
||
|
|
#endif
|
||
|
|
RCC->APB1RSTR |= RCC_APB1RSTR_USBRST; // Reset USB Device
|
||
|
|
|
||
|
|
// Reset variables
|
||
|
|
setup_received = 0U;
|
||
|
|
memset((void *)&usbd_state, 0, sizeof(usbd_state));
|
||
|
|
memset((void *)ep, 0, sizeof(ep));
|
||
|
|
|
||
|
|
RCC->APB1ENR &= ~RCC_APB1ENR_USBEN; // Disable USB Device clock
|
||
|
|
|
||
|
|
break;
|
||
|
|
|
||
|
|
case ARM_POWER_FULL:
|
||
|
|
if (hw_initialized == false) {
|
||
|
|
return ARM_DRIVER_ERROR;
|
||
|
|
}
|
||
|
|
if (hw_powered == true) {
|
||
|
|
return ARM_DRIVER_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
RCC->APB1ENR |= RCC_APB1ENR_USBEN; // Enable USB Device clock
|
||
|
|
RCC->APB1RSTR |= RCC_APB1RSTR_USBRST; // Reset USB Device
|
||
|
|
osDelay(1); // Wait 1 ms
|
||
|
|
RCC->APB1RSTR &= ~RCC_APB1RSTR_USBRST; // Reset USB Device
|
||
|
|
|
||
|
|
USBD_Reset (); // Reset variables and endpoint settings
|
||
|
|
|
||
|
|
hw_powered = true; // Set powered flag
|
||
|
|
|
||
|
|
NVIC_EnableIRQ (USB_LP_CAN1_RX0_IRQn); // Enable interrupt
|
||
|
|
break;
|
||
|
|
|
||
|
|
default:
|
||
|
|
return ARM_DRIVER_ERROR_UNSUPPORTED;
|
||
|
|
}
|
||
|
|
|
||
|
|
return ARM_DRIVER_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
\fn int32_t USBD_DeviceConnect (void)
|
||
|
|
\brief Connect USB Device.
|
||
|
|
\return \ref execution_status
|
||
|
|
*/
|
||
|
|
static int32_t USBD_DeviceConnect (void) {
|
||
|
|
|
||
|
|
if (hw_powered == false) { return ARM_DRIVER_ERROR; }
|
||
|
|
|
||
|
|
// Soft connect
|
||
|
|
#if (RTE_USB_DEVICE_CON_PIN)
|
||
|
|
GPIO_PinWrite (RTE_USB_DEVICE_CON_PORT, RTE_USB_DEVICE_CON_BIT, RTE_USB_DEVICE_CON_ACTIVE);
|
||
|
|
#endif
|
||
|
|
|
||
|
|
CNTR = CNTR_FRES; // Force USB Reset
|
||
|
|
CNTR = 0;
|
||
|
|
ISTR = 0; // Clear Interrupt Status
|
||
|
|
CNTR = CNTR_RESETM | CNTR_SUSPM | CNTR_WKUPM; // USB Interrupt Mask
|
||
|
|
|
||
|
|
return ARM_DRIVER_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
\fn int32_t USBD_DeviceDisconnect (void)
|
||
|
|
\brief Disconnect USB Device.
|
||
|
|
\return \ref execution_status
|
||
|
|
*/
|
||
|
|
static int32_t USBD_DeviceDisconnect (void) {
|
||
|
|
|
||
|
|
if (hw_powered == false) { return ARM_DRIVER_ERROR; }
|
||
|
|
|
||
|
|
CNTR = CNTR_FRES | CNTR_PDWN; // Switch Off USB Device
|
||
|
|
|
||
|
|
// Soft disconnect
|
||
|
|
#if (RTE_USB_DEVICE_CON_PIN)
|
||
|
|
GPIO_PinWrite (RTE_USB_DEVICE_CON_PORT, RTE_USB_DEVICE_CON_BIT, !RTE_USB_DEVICE_CON_ACTIVE);
|
||
|
|
#endif
|
||
|
|
|
||
|
|
return ARM_DRIVER_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
\fn ARM_USBD_STATE USBD_DeviceGetState (void)
|
||
|
|
\brief Get current USB Device State.
|
||
|
|
\return Device State \ref ARM_USBD_STATE
|
||
|
|
*/
|
||
|
|
static ARM_USBD_STATE USBD_DeviceGetState (void) {
|
||
|
|
return usbd_state;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
\fn int32_t USBD_DeviceRemoteWakeup (void)
|
||
|
|
\brief Trigger USB Remote Wakeup.
|
||
|
|
\return \ref execution_status
|
||
|
|
*/
|
||
|
|
static int32_t USBD_DeviceRemoteWakeup (void) {
|
||
|
|
|
||
|
|
if (hw_powered == false) { return ARM_DRIVER_ERROR; }
|
||
|
|
|
||
|
|
CNTR |= CNTR; // Remote wakeup signaling
|
||
|
|
osDelay(2U);
|
||
|
|
CNTR &= ~CNTR;
|
||
|
|
|
||
|
|
return ARM_DRIVER_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
\fn int32_t USBD_DeviceSetAddress (uint8_t dev_addr)
|
||
|
|
\brief Set USB Device Address.
|
||
|
|
\param[in] dev_addr Device Address
|
||
|
|
\return \ref execution_status
|
||
|
|
*/
|
||
|
|
static int32_t USBD_DeviceSetAddress (uint8_t dev_addr) {
|
||
|
|
|
||
|
|
if (hw_powered == false) { return ARM_DRIVER_ERROR; }
|
||
|
|
|
||
|
|
DADDR = DADDR_EF | dev_addr;
|
||
|
|
|
||
|
|
return ARM_DRIVER_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
\fn int32_t USBD_ReadSetupPacket (uint8_t *setup)
|
||
|
|
\brief Read setup packet received over Control Endpoint.
|
||
|
|
\param[out] setup Pointer to buffer for setup packet
|
||
|
|
\return \ref execution_status
|
||
|
|
*/
|
||
|
|
static int32_t USBD_ReadSetupPacket (uint8_t *setup) {
|
||
|
|
|
||
|
|
if (hw_powered == false) { return ARM_DRIVER_ERROR; }
|
||
|
|
if (setup_received == 0U) { return ARM_DRIVER_ERROR; }
|
||
|
|
|
||
|
|
setup_received = 0U;
|
||
|
|
memcpy(setup, setup_packet, 8);
|
||
|
|
|
||
|
|
if (setup_received != 0U) { // If new setup packet was received while this was being read
|
||
|
|
return ARM_DRIVER_ERROR;
|
||
|
|
}
|
||
|
|
|
||
|
|
return ARM_DRIVER_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
\fn int32_t USBD_EndpointConfigure (uint8_t ep_addr,
|
||
|
|
uint8_t ep_type,
|
||
|
|
uint16_t ep_max_packet_size)
|
||
|
|
\brief Configure USB Endpoint.
|
||
|
|
\param[in] ep_addr Endpoint Address
|
||
|
|
- ep_addr.0..7: Address
|
||
|
|
- ep_addr.7: Direction
|
||
|
|
\param[in] ep_type Endpoint Type (ARM_USB_ENDPOINT_xxx)
|
||
|
|
\param[in] ep_max_packet_size Endpoint Maximum Packet Size
|
||
|
|
\return \ref execution_status
|
||
|
|
*/
|
||
|
|
static int32_t USBD_EndpointConfigure (uint8_t ep_addr,
|
||
|
|
uint8_t ep_type,
|
||
|
|
uint16_t ep_max_packet_size) {
|
||
|
|
volatile ENDPOINT_t *ptr_ep;
|
||
|
|
uint8_t ep_num;
|
||
|
|
uint16_t ep_mps;
|
||
|
|
bool ep_dir;
|
||
|
|
uint32_t ep_reg;
|
||
|
|
|
||
|
|
ep_num = EP_NUM(ep_addr);
|
||
|
|
if (ep_num > USBD_MAX_ENDPOINT_NUM) { return ARM_DRIVER_ERROR; }
|
||
|
|
if (hw_powered == false) { return ARM_DRIVER_ERROR; }
|
||
|
|
|
||
|
|
ptr_ep = &ep[EP_ID(ep_addr)];
|
||
|
|
if (ptr_ep->active != 0U) { return ARM_DRIVER_ERROR_BUSY; }
|
||
|
|
|
||
|
|
ep_mps = ep_max_packet_size & ARM_USB_ENDPOINT_MAX_PACKET_SIZE_MASK;
|
||
|
|
ep_dir = (ep_addr & ARM_USB_ENDPOINT_DIRECTION_MASK) == ARM_USB_ENDPOINT_DIRECTION_MASK;
|
||
|
|
|
||
|
|
// Check Endpoint buffer size configuration
|
||
|
|
if ((ep_mps + EP_buff_offset[EP_ID(ep_addr)]) > EP_buff_offset[EP_ID(ep_addr) + 1]) {
|
||
|
|
// Configured Endpoint buffer is too small
|
||
|
|
return ARM_DRIVER_ERROR;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Clear Endpoint transfer and configuration information
|
||
|
|
memset((void *)(ptr_ep), 0, sizeof (ENDPOINT_t));
|
||
|
|
|
||
|
|
// Set maximum packet size to requested
|
||
|
|
ptr_ep->max_packet_size = ep_mps;
|
||
|
|
|
||
|
|
if (ep_dir != 0U) { // IN Endpoint
|
||
|
|
(pBUF_DSCR + ep_num)->ADDR_TX = EP_buff_offset[EP_ID(ep_addr)];
|
||
|
|
} else { // OUT Endpoint
|
||
|
|
(pBUF_DSCR + ep_num)->ADDR_RX = EP_buff_offset[EP_ID(ep_addr)];
|
||
|
|
if (ep_mps > 62) {
|
||
|
|
ep_mps = (ep_mps + 31) & ~31;
|
||
|
|
(pBUF_DSCR + ep_num)->COUNT_RX = ((ep_mps << 5) - 1) | 0x8000;
|
||
|
|
} else {
|
||
|
|
ep_mps = (ep_mps + 1) & ~1;
|
||
|
|
(pBUF_DSCR + ep_num)->COUNT_RX = ep_mps << 9;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
switch (ep_type) {
|
||
|
|
case ARM_USB_ENDPOINT_CONTROL:
|
||
|
|
ep_reg = EP_CONTROL;
|
||
|
|
break;
|
||
|
|
case ARM_USB_ENDPOINT_ISOCHRONOUS:
|
||
|
|
ep_reg = EP_ISOCHRONOUS;
|
||
|
|
break;
|
||
|
|
case ARM_USB_ENDPOINT_BULK:
|
||
|
|
ep_reg = EP_BULK;
|
||
|
|
break;
|
||
|
|
case ARM_USB_ENDPOINT_INTERRUPT:
|
||
|
|
ep_reg = EP_INTERRUPT;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (ep_addr == 0U) {
|
||
|
|
// Enable Endpoint 0 to receive Setup and OUT packets
|
||
|
|
EPxREG(0) = EP_CONTROL | EP_RX_VALID;
|
||
|
|
} else if (ep_addr != 0x80U){
|
||
|
|
ep_reg |= ep_num;
|
||
|
|
EPxREG(ep_num) = ep_reg;
|
||
|
|
|
||
|
|
if (ep_dir != 0U) { // IN Endpoint
|
||
|
|
IN_EP_RESET(ep_num);
|
||
|
|
IN_EP_Status(ep_num, EP_TX_NAK);
|
||
|
|
} else { // OUT Endpoint
|
||
|
|
OUT_EP_RESET(ep_num);
|
||
|
|
OUT_EP_Status(ep_num, EP_RX_NAK);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return ARM_DRIVER_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
\fn int32_t USBD_EndpointUnconfigure (uint8_t ep_addr)
|
||
|
|
\brief Unconfigure USB Endpoint.
|
||
|
|
\param[in] ep_addr Endpoint Address
|
||
|
|
- ep_addr.0..7: Address
|
||
|
|
- ep_addr.7: Direction
|
||
|
|
\return \ref execution_status
|
||
|
|
*/
|
||
|
|
static int32_t USBD_EndpointUnconfigure (uint8_t ep_addr) {
|
||
|
|
volatile ENDPOINT_t *ptr_ep;
|
||
|
|
uint8_t ep_num;
|
||
|
|
bool ep_dir;
|
||
|
|
|
||
|
|
ep_num = EP_NUM(ep_addr);
|
||
|
|
if (ep_num > USBD_MAX_ENDPOINT_NUM) { return ARM_DRIVER_ERROR; }
|
||
|
|
if (hw_powered == false) { return ARM_DRIVER_ERROR; }
|
||
|
|
|
||
|
|
ptr_ep = &ep[EP_ID(ep_addr)];
|
||
|
|
if (ptr_ep->active != 0U) { return ARM_DRIVER_ERROR_BUSY; }
|
||
|
|
|
||
|
|
ep_dir = (ep_addr & ARM_USB_ENDPOINT_DIRECTION_MASK) == ARM_USB_ENDPOINT_DIRECTION_MASK;
|
||
|
|
|
||
|
|
if (ep_dir != 0U) { // IN Endpoint
|
||
|
|
IN_EP_RESET(ep_num);
|
||
|
|
IN_EP_Status(ep_num, EP_TX_DIS);
|
||
|
|
} else { // OUT Endpoint
|
||
|
|
OUT_EP_RESET(ep_num);
|
||
|
|
OUT_EP_Status(ep_num, EP_RX_DIS);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Clear Endpoint transfer and configuration information
|
||
|
|
memset((void *)(ptr_ep), 0, sizeof (ENDPOINT_t));
|
||
|
|
|
||
|
|
return ARM_DRIVER_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
\fn int32_t USBD_EndpointStall (uint8_t ep_addr, bool stall)
|
||
|
|
\brief Set/Clear Stall for USB Endpoint.
|
||
|
|
\param[in] ep_addr Endpoint Address
|
||
|
|
- ep_addr.0..7: Address
|
||
|
|
- ep_addr.7: Direction
|
||
|
|
\param[in] stall Operation
|
||
|
|
- \b false Clear
|
||
|
|
- \b true Set
|
||
|
|
\return \ref execution_status
|
||
|
|
*/
|
||
|
|
static int32_t USBD_EndpointStall (uint8_t ep_addr, bool stall) {
|
||
|
|
volatile ENDPOINT_t *ptr_ep;
|
||
|
|
uint8_t ep_num;
|
||
|
|
bool ep_dir;
|
||
|
|
|
||
|
|
ep_num = EP_NUM(ep_addr);
|
||
|
|
if (ep_num > USBD_MAX_ENDPOINT_NUM) { return ARM_DRIVER_ERROR; }
|
||
|
|
if (hw_powered == false) { return ARM_DRIVER_ERROR; }
|
||
|
|
|
||
|
|
ptr_ep = &ep[EP_ID(ep_addr)];
|
||
|
|
if (ptr_ep->active != 0U) { return ARM_DRIVER_ERROR_BUSY; }
|
||
|
|
|
||
|
|
ep_dir = (ep_addr & ARM_USB_ENDPOINT_DIRECTION_MASK) == ARM_USB_ENDPOINT_DIRECTION_MASK;
|
||
|
|
|
||
|
|
if (stall == true) {
|
||
|
|
if (ep_dir != 0U) { // IN Endpoint
|
||
|
|
IN_EP_Status(ep_num, EP_TX_STALL); // Stall IN Endpoint
|
||
|
|
} else { // OUT Endpoint
|
||
|
|
OUT_EP_Status(ep_num, EP_RX_STALL); // Stall OUT Endpoint
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
if (ep_dir != 0U) { // IN Endpoint
|
||
|
|
IN_EP_RESET(ep_num); // Reset DTog Bits
|
||
|
|
IN_EP_Status(ep_num, EP_TX_NAK); // Clear STALL
|
||
|
|
} else { // OUT Endpoint
|
||
|
|
OUT_EP_RESET(ep_num); // Reset DTog Bits
|
||
|
|
OUT_EP_Status(ep_num, EP_RX_NAK); // Clear Stall
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return ARM_DRIVER_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
\fn int32_t USBD_EndpointTransfer (uint8_t ep_addr, uint8_t *data, uint32_t num)
|
||
|
|
\brief Read data from or Write data to USB Endpoint.
|
||
|
|
\param[in] ep_addr Endpoint Address
|
||
|
|
- ep_addr.0..7: Address
|
||
|
|
- ep_addr.7: Direction
|
||
|
|
\param[out] data Pointer to buffer for data to read or with data to write
|
||
|
|
\param[in] num Number of data bytes to transfer
|
||
|
|
\return \ref execution_status
|
||
|
|
*/
|
||
|
|
static int32_t USBD_EndpointTransfer (uint8_t ep_addr, uint8_t *data, uint32_t num) {
|
||
|
|
volatile ENDPOINT_t *ptr_ep;
|
||
|
|
uint8_t ep_num;
|
||
|
|
bool ep_dir;
|
||
|
|
|
||
|
|
ep_num = EP_NUM(ep_addr);
|
||
|
|
if (ep_num > USBD_MAX_ENDPOINT_NUM) { return ARM_DRIVER_ERROR; }
|
||
|
|
if (hw_powered == false) { return ARM_DRIVER_ERROR; }
|
||
|
|
|
||
|
|
ptr_ep = &ep[EP_ID(ep_addr)];
|
||
|
|
if (ptr_ep->active != 0U) { return ARM_DRIVER_ERROR_BUSY; }
|
||
|
|
|
||
|
|
ep_dir = (ep_addr & ARM_USB_ENDPOINT_DIRECTION_MASK) == ARM_USB_ENDPOINT_DIRECTION_MASK;
|
||
|
|
|
||
|
|
ptr_ep->active = 1U;
|
||
|
|
|
||
|
|
ptr_ep->data = data;
|
||
|
|
ptr_ep->num = num;
|
||
|
|
ptr_ep->num_transferred_total = 0U;
|
||
|
|
ptr_ep->num_transferring = 0U;
|
||
|
|
|
||
|
|
if (ep_dir != 0U) { // IN Endpoint
|
||
|
|
USBD_EP_HW_Write (ep_addr); // Write data to Endpoint buffer
|
||
|
|
} else { // OUT Endpoint
|
||
|
|
OUT_EP_Status(ep_num, EP_RX_VALID); // OUT EP able to receive data
|
||
|
|
}
|
||
|
|
|
||
|
|
return ARM_DRIVER_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
\fn uint32_t USBD_EndpointTransferGetResult (uint8_t ep_addr)
|
||
|
|
\brief Get result of USB Endpoint transfer.
|
||
|
|
\param[in] ep_addr Endpoint Address
|
||
|
|
- ep_addr.0..7: Address
|
||
|
|
- ep_addr.7: Direction
|
||
|
|
\return number of successfully transferred data bytes
|
||
|
|
*/
|
||
|
|
static uint32_t USBD_EndpointTransferGetResult (uint8_t ep_addr) {
|
||
|
|
|
||
|
|
if (EP_NUM(ep_addr) > USBD_MAX_ENDPOINT_NUM) { return 0U; }
|
||
|
|
|
||
|
|
return (ep[EP_ID(ep_addr)].num_transferred_total);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
\fn int32_t USBD_EndpointTransferAbort (uint8_t ep_addr)
|
||
|
|
\brief Abort current USB Endpoint transfer.
|
||
|
|
\param[in] ep_addr Endpoint Address
|
||
|
|
- ep_addr.0..7: Address
|
||
|
|
- ep_addr.7: Direction
|
||
|
|
\return \ref execution_status
|
||
|
|
*/
|
||
|
|
static int32_t USBD_EndpointTransferAbort (uint8_t ep_addr) {
|
||
|
|
volatile ENDPOINT_t *ptr_ep;
|
||
|
|
uint8_t ep_num;
|
||
|
|
bool ep_dir;
|
||
|
|
|
||
|
|
ep_num = EP_NUM(ep_addr);
|
||
|
|
if (ep_num > USBD_MAX_ENDPOINT_NUM) { return ARM_DRIVER_ERROR; }
|
||
|
|
if (hw_powered == false) { return ARM_DRIVER_ERROR; }
|
||
|
|
|
||
|
|
ep_dir = (ep_addr & ARM_USB_ENDPOINT_DIRECTION_MASK) == ARM_USB_ENDPOINT_DIRECTION_MASK;
|
||
|
|
ptr_ep = &ep[EP_ID(ep_addr)];
|
||
|
|
|
||
|
|
ptr_ep->num = 0U;
|
||
|
|
|
||
|
|
if (ep_dir != 0U) { // IN Endpoint
|
||
|
|
IN_EP_Status(ep_num, EP_TX_NAK); // Set NAK
|
||
|
|
} else { // OUT Endpoint
|
||
|
|
OUT_EP_Status(ep_num, EP_RX_NAK); // Set NAK
|
||
|
|
}
|
||
|
|
|
||
|
|
ptr_ep->active = 0U;
|
||
|
|
|
||
|
|
return ARM_DRIVER_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
\fn uint16_t USBD_GetFrameNumber (void)
|
||
|
|
\brief Get current USB Frame Number.
|
||
|
|
\return Frame Number
|
||
|
|
*/
|
||
|
|
static uint16_t USBD_GetFrameNumber (void) {
|
||
|
|
|
||
|
|
if (hw_powered == false) { return 0U; }
|
||
|
|
|
||
|
|
return (FNR & FNR_FN);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
\fn void USB_LP_CAN1_RX0_IRQHandler (void)
|
||
|
|
\brief USB Device Interrupt Routine (IRQ).
|
||
|
|
*/
|
||
|
|
void USB_LP_CAN1_RX0_IRQHandler (void) {
|
||
|
|
__packed uint16_t *ptr_dest;
|
||
|
|
volatile uint32_t *ptr_src;
|
||
|
|
volatile ENDPOINT_t *ptr_ep;
|
||
|
|
uint32_t istr, ep_num, val, i;
|
||
|
|
|
||
|
|
istr = ISTR;
|
||
|
|
|
||
|
|
// Reset interrupt
|
||
|
|
if (istr & ISTR_RESET) {
|
||
|
|
USBD_Reset();
|
||
|
|
SignalDeviceEvent(ARM_USBD_EVENT_RESET);
|
||
|
|
ISTR = ~ISTR_RESET;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Suspend interrupt
|
||
|
|
if (istr & ISTR_SUSP) {
|
||
|
|
CNTR |= CNTR_SUSPM;
|
||
|
|
usbd_state.active = 0U;
|
||
|
|
SignalDeviceEvent(ARM_USBD_EVENT_SUSPEND);
|
||
|
|
ISTR = ~ISTR_SUSP;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Resume interrupt
|
||
|
|
if (istr & ISTR_WKUP) {
|
||
|
|
usbd_state.active = 1U;
|
||
|
|
CNTR &= ~CNTR_SUSPM;
|
||
|
|
SignalDeviceEvent(ARM_USBD_EVENT_RESUME);
|
||
|
|
ISTR = ~ISTR_WKUP;
|
||
|
|
}
|
||
|
|
|
||
|
|
// PMA Over/underrun
|
||
|
|
if (istr & ISTR_PMAOVR) {
|
||
|
|
ISTR = ~ISTR_PMAOVR;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Error: No Answer, CRC Error, Bit Stuff Error, Frame Format Error
|
||
|
|
if (istr & ISTR_ERR) {
|
||
|
|
ISTR = ~ISTR_ERR;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Endpoint interrupts
|
||
|
|
if ((istr = ISTR) & ISTR_CTR) {
|
||
|
|
// ISTR = ~ISTR_CTR;
|
||
|
|
|
||
|
|
ep_num = istr & ISTR_EP_ID;
|
||
|
|
|
||
|
|
val = EPxREG(ep_num);
|
||
|
|
if (val & EP_CTR_RX) {
|
||
|
|
ptr_ep = &ep[EP_ID(ep_num)];
|
||
|
|
EPxREG(ep_num) = val & ~EP_CTR_RX & EP_MASK;
|
||
|
|
|
||
|
|
// Setup Packet
|
||
|
|
if (val & EP_SETUP) {
|
||
|
|
// Read Setup Packet
|
||
|
|
ptr_src = (uint32_t *)(USB_PMA_ADDR + 2*((pBUF_DSCR)->ADDR_RX));
|
||
|
|
ptr_dest = (__packed uint16_t *)(setup_packet);
|
||
|
|
for (i = 0U; i < 4U; i++) {
|
||
|
|
*ptr_dest++ = *ptr_src++;
|
||
|
|
}
|
||
|
|
setup_received = 1U;
|
||
|
|
SignalEndpointEvent(ep_num, ARM_USBD_EVENT_SETUP);
|
||
|
|
} else {
|
||
|
|
// OUT Packet
|
||
|
|
USBD_EP_HW_Read(ep_num);
|
||
|
|
if (ptr_ep->num != 0U) {
|
||
|
|
OUT_EP_Status(ep_num, EP_RX_VALID);
|
||
|
|
} else {
|
||
|
|
ptr_ep->active = 0U;
|
||
|
|
SignalEndpointEvent(ep_num, ARM_USBD_EVENT_OUT);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// IN Packet
|
||
|
|
if (val & EP_CTR_TX) {
|
||
|
|
ptr_ep = &ep[EP_ID(ep_num | ARM_USB_ENDPOINT_DIRECTION_MASK)];
|
||
|
|
EPxREG(ep_num) = val & ~EP_CTR_TX & EP_MASK;
|
||
|
|
ptr_ep->num_transferred_total += ptr_ep->num_transferring;
|
||
|
|
if (ptr_ep->num == 0U) {
|
||
|
|
ptr_ep->data = NULL;
|
||
|
|
ptr_ep->active = 0U;
|
||
|
|
SignalEndpointEvent(ep_num | ARM_USB_ENDPOINT_DIRECTION_MASK, ARM_USBD_EVENT_IN);
|
||
|
|
} else {
|
||
|
|
USBD_EP_HW_Write(ep_num | ARM_USB_ENDPOINT_DIRECTION_MASK);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
ARM_DRIVER_USBD Driver_USBD0 = {
|
||
|
|
USBD_GetVersion,
|
||
|
|
USBD_GetCapabilities,
|
||
|
|
USBD_Initialize,
|
||
|
|
USBD_Uninitialize,
|
||
|
|
USBD_PowerControl,
|
||
|
|
USBD_DeviceConnect,
|
||
|
|
USBD_DeviceDisconnect,
|
||
|
|
USBD_DeviceGetState,
|
||
|
|
USBD_DeviceRemoteWakeup,
|
||
|
|
USBD_DeviceSetAddress,
|
||
|
|
USBD_ReadSetupPacket,
|
||
|
|
USBD_EndpointConfigure,
|
||
|
|
USBD_EndpointUnconfigure,
|
||
|
|
USBD_EndpointStall,
|
||
|
|
USBD_EndpointTransfer,
|
||
|
|
USBD_EndpointTransferGetResult,
|
||
|
|
USBD_EndpointTransferAbort,
|
||
|
|
USBD_GetFrameNumber
|
||
|
|
};
|