MoistureSoftware/.pack/Keil/STM32F1xx_DFP.2.3.0/RTE_Driver/USBD_STM32F10x.c

975 lines
30 KiB
C
Raw Normal View History

2025-09-28 09:17:22 +00:00
/* -----------------------------------------------------------------------------
* 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
};