mirror of
https://github.com/0xFEEDC0DE64/arduino-esp32.git
synced 2025-06-30 12:30:59 +02:00
IDF master 1d7068e4b (#5257)
esp-dsp: master 7cc5073 esp-face: master 420fc7e esp-rainmaker: f1b82c7 esp32-camera: master 7a06a7e esp_littlefs: master b58f00c
This commit is contained in:
@ -402,6 +402,12 @@ static inline void spi_flash_ll_set_hold(spi_dev_t *dev, uint32_t hold_n)
|
||||
dev->user.cs_hold = (hold_n > 0? 1: 0);
|
||||
}
|
||||
|
||||
static inline void spi_flash_ll_set_cs_setup(spi_dev_t *dev, uint32_t cs_setup_time)
|
||||
{
|
||||
dev->user.cs_setup = (cs_setup_time > 0 ? 1 : 0);
|
||||
dev->ctrl2.setup_time = cs_setup_time - 1;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -96,7 +96,7 @@ static inline void touch_ll_set_sleep_time(uint16_t sleep_time)
|
||||
*/
|
||||
static inline void touch_ll_get_sleep_time(uint16_t *sleep_time)
|
||||
{
|
||||
*sleep_time = SENS.sar_touch_ctrl1.touch_meas_delay;
|
||||
*sleep_time = SENS.sar_touch_ctrl2.touch_sleep_cycles;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -56,9 +56,9 @@ typedef enum {
|
||||
*/
|
||||
typedef enum {
|
||||
ADC_ATTEN_DB_0 = 0, /*!<No input attenumation, ADC can measure up to approx. 800 mV. */
|
||||
ADC_ATTEN_DB_2_5 = 1, /*!<The input voltage of ADC will be attenuated, extending the range of measurement to up to approx. 1100 mV. */
|
||||
ADC_ATTEN_DB_6 = 2, /*!<The input voltage of ADC will be attenuated, extending the range of measurement to up to approx. 1350 mV. */
|
||||
ADC_ATTEN_DB_11 = 3, /*!<The input voltage of ADC will be attenuated, extending the range of measurement to up to approx. 2600 mV. */
|
||||
ADC_ATTEN_DB_2_5 = 1, /*!<The input voltage of ADC will be attenuated extending the range of measurement by about 2.5 dB (1.33 x) */
|
||||
ADC_ATTEN_DB_6 = 2, /*!<The input voltage of ADC will be attenuated extending the range of measurement by about 6 dB (2 x) */
|
||||
ADC_ATTEN_DB_11 = 3, /*!<The input voltage of ADC will be attenuated extending the range of measurement by about 11 dB (3.55 x) */
|
||||
ADC_ATTEN_MAX,
|
||||
} adc_atten_t;
|
||||
|
||||
|
@ -42,7 +42,7 @@ typedef struct {
|
||||
int cs_num; ///< Which cs pin is used, 0-2.
|
||||
struct {
|
||||
uint8_t extra_dummy; ///< Pre-calculated extra dummy used for compensation
|
||||
uint8_t reserved1; ///< Reserved, set to 0.
|
||||
uint8_t cs_setup; ///< (cycles-1) of prepare phase by spi clock.
|
||||
uint8_t cs_hold; ///< CS hold time config used by the host
|
||||
uint8_t reserved2; ///< Reserved, set to 0.
|
||||
};
|
||||
@ -63,6 +63,7 @@ typedef struct {
|
||||
int input_delay_ns; ///< Input delay on the MISO pin after the launch clock, used for timing compensation.
|
||||
esp_flash_speed_t speed;///< SPI flash clock speed to work at.
|
||||
uint32_t cs_hold; ///< CS hold time config used by the host
|
||||
uint8_t cs_setup; ///< (cycles-1) of prepare phase by spi clock
|
||||
bool auto_sus_en; ///< Auto suspend feature enable bit 1: enable, 0: disable.
|
||||
} spi_flash_hal_config_t;
|
||||
|
||||
|
72
tools/sdk/esp32/include/hal/include/hal/usb_types_private.h
Normal file
72
tools/sdk/esp32/include/hal/include/hal/usb_types_private.h
Normal file
@ -0,0 +1,72 @@
|
||||
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// 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.
|
||||
|
||||
/*
|
||||
Note: This header file contains USB2.0 related types and macros that can be used by code specific to the DWC_OTG
|
||||
controller (i.e., the HW specific layers of the USB host stack). Thus, this header is only meant to be used below (and
|
||||
including) the HAL layer. For types and macros that are HW implementation agnostic (i.e., HCD layer and above), add them
|
||||
to the "usb.h" header instead.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief USB speeds supported by the DWC OTG controller
|
||||
*/
|
||||
typedef enum {
|
||||
USB_PRIV_SPEED_FULL,
|
||||
USB_PRIV_SPEED_LOW,
|
||||
} usb_priv_speed_t;
|
||||
|
||||
/**
|
||||
* @brief USB transfer types supported by the DWC OTG controller
|
||||
*/
|
||||
typedef enum {
|
||||
USB_PRIV_XFER_TYPE_CTRL,
|
||||
USB_PRIV_XFER_TYPE_ISOCHRONOUS,
|
||||
USB_PRIV_XFER_TYPE_BULK,
|
||||
USB_PRIV_XFER_TYPE_INTR,
|
||||
} usb_priv_xfer_type_t;
|
||||
|
||||
/**
|
||||
* @brief Enumeration of different possible lengths of the periodic frame list
|
||||
*/
|
||||
typedef enum {
|
||||
USB_HAL_FRAME_LIST_LEN_8 = 8,
|
||||
USB_HAL_FRAME_LIST_LEN_16 = 16,
|
||||
USB_HAL_FRAME_LIST_LEN_32 = 32,
|
||||
USB_HAL_FRAME_LIST_LEN_64 = 64,
|
||||
} usb_hal_frame_list_len_t;
|
||||
|
||||
/**
|
||||
* @brief Support intervals in number of USB frames (i.e., 1ms)
|
||||
*/
|
||||
typedef enum {
|
||||
USB_HAL_INTERVAL_1 = 1,
|
||||
USB_HAL_INTERVAL_2 = 2,
|
||||
USB_HAL_INTERVAL_4 = 4,
|
||||
USB_HAL_INTERVAL_8 = 8,
|
||||
USB_HAL_INTERVAL_16 = 16,
|
||||
USB_HAL_INTERVAL_32 = 32,
|
||||
USB_HAL_INTERVAL_64 = 64,
|
||||
} usb_hal_interval_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
820
tools/sdk/esp32/include/hal/include/hal/usbh_hal.h
Normal file
820
tools/sdk/esp32/include/hal/include/hal/usbh_hal.h
Normal file
@ -0,0 +1,820 @@
|
||||
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
NOTE: Thread safety is the responsibility fo the HAL user. All USB Host HAL
|
||||
functions must be called from critical sections unless specified otherwise
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include "soc/usbh_struct.h"
|
||||
#include "soc/usb_wrap_struct.h"
|
||||
#include "hal/usbh_ll.h"
|
||||
#include "hal/usb_types_private.h"
|
||||
|
||||
// ------------------------------------------------ Macros and Types ---------------------------------------------------
|
||||
|
||||
// ------------------ Constants/Configs --------------------
|
||||
|
||||
#define USBH_HAL_DMA_MEM_ALIGN 512
|
||||
#define USBH_HAL_FRAME_LIST_MEM_ALIGN 512 //The frame list needs to be 512 bytes aligned (contrary to the databook)
|
||||
#define USBH_HAL_NUM_CHAN 8
|
||||
#define USBH_HAL_XFER_DESC_SIZE (sizeof(usbh_ll_dma_qtd_t))
|
||||
#define USBH_HAL_FIFO_TOTAL_USABLE_LINES 200 //Although we have a 256 lines, only 200 lines are usuable due to EPINFO_CTL
|
||||
|
||||
/**
|
||||
* @brief FIFO size configuration structure
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t rx_fifo_lines; /**< Size of the RX FIFO in terms the number of FIFO lines */
|
||||
uint32_t nptx_fifo_lines; /**< Size of the Non-periodic FIFO in terms the number of FIFO lines */
|
||||
uint32_t ptx_fifo_lines; /**< Size of the Periodic FIFO in terms the number of FIFO lines */
|
||||
} usbh_hal_fifo_config_t;
|
||||
|
||||
// --------------------- HAL States ------------------------
|
||||
|
||||
/**
|
||||
* @brief Channel states
|
||||
*/
|
||||
typedef enum {
|
||||
USBH_HAL_CHAN_STATE_HALTED = 0, /**< The channel is halted. No transfer descriptor list is being executed */
|
||||
USBH_HAL_CHAN_STATE_ACTIVE, /**< The channel is active. A transfer descriptor list is being executed */
|
||||
USBH_HAL_CHAN_STATE_ERROR, /**< The channel is in the error state */
|
||||
} usbh_hal_chan_state_t;
|
||||
|
||||
// --------------------- HAL Events ------------------------
|
||||
|
||||
/**
|
||||
* @brief Host port HAL events
|
||||
*/
|
||||
typedef enum {
|
||||
USBH_HAL_PORT_EVENT_NONE, /**< No event occurred, or could not decode interrupt */
|
||||
USBH_HAL_PORT_EVENT_CHAN, /**< A channel event has occurred. Call the the channel event handler instead */
|
||||
USBH_HAL_PORT_EVENT_CONN, /**< The host port has detected a connection */
|
||||
USBH_HAL_PORT_EVENT_DISCONN, /**< The host port has been disconnected */
|
||||
USBH_HAL_PORT_EVENT_ENABLED, /**< The host port has been enabled (i.e., connected to a device that has been reset. Started sending SOFs) */
|
||||
USBH_HAL_PORT_EVENT_DISABLED, /**< The host port has been disabled (no more SOFs). Could be due to disable/reset request, or a port error (e.g. port babble condition. See 11.8.1 of USB2.0 spec) */
|
||||
USBH_HAL_PORT_EVENT_OVRCUR, /**< The host port has encountered an overcurrent condition */
|
||||
USBH_HAL_PORT_EVENT_OVRCUR_CLR, /**< The host port has been cleared of the overcurrent condition */
|
||||
} usbh_hal_port_event_t;
|
||||
|
||||
/**
|
||||
* @brief Channel events
|
||||
*/
|
||||
typedef enum {
|
||||
USBH_HAL_CHAN_EVENT_CPLT, /**< The channel has completed execution of a transfer descriptor that had the USBH_HAL_XFER_DESC_FLAG_HOC flag set. Channel is now halted */
|
||||
USBH_HAL_CHAN_EVENT_ERROR, /**< The channel has encountered an error. Channel is now halted. */
|
||||
USBH_HAL_CHAN_EVENT_HALT_REQ, /**< The channel has been successfully halted as requested */
|
||||
USBH_HAL_CHAN_EVENT_NONE, /**< No event (interrupt ran for internal processing) */
|
||||
} usbh_hal_chan_event_t;
|
||||
|
||||
// --------------------- HAL Errors ------------------------
|
||||
|
||||
/**
|
||||
* @brief Channel errors
|
||||
*/
|
||||
typedef enum {
|
||||
USBH_HAL_CHAN_ERROR_XCS_XACT = 0, /**< Excessive (three consecutive) transaction errors (e.g., no response, bad CRC etc */
|
||||
USBH_HAL_CHAN_ERROR_BNA, /**< Buffer Not Available error (i.e., An inactive transfer descriptor was fetched by the channel) */
|
||||
USBH_HAL_CHAN_ERROR_PKT_BBL, /**< Packet babbler error (packet exceeded MPS) */
|
||||
USBH_HAL_CHAN_ERROR_STALL, /**< STALL response received */
|
||||
} usbh_hal_chan_error_t;
|
||||
|
||||
// ------------- Transfer Descriptor Related ---------------
|
||||
|
||||
/**
|
||||
* @brief Flags used to describe the type of transfer descriptor to fill
|
||||
*/
|
||||
#define USBH_HAL_XFER_DESC_FLAG_IN 0x01 /**< Indicates this transfer descriptor is of the IN direction */
|
||||
#define USBH_HAL_XFER_DESC_FLAG_SETUP 0x02 /**< Indicates this transfer descriptor is an OUT setup */
|
||||
#define USBH_HAL_XFER_DESC_FLAG_HOC 0x04 /**< Indicates that the channel will be halted after this transfer descriptor completes */
|
||||
|
||||
/**
|
||||
* @brief Status value of a transfer descriptor
|
||||
*
|
||||
* A transfer descriptor's status remains unexecuted until the entire transfer descriptor completes (either successfully
|
||||
* or an error). Therefore, if a channel halt is requested before a transfer descriptor completes, the transfer
|
||||
* descriptor remains unexecuted.
|
||||
*/
|
||||
#define USBH_HAL_XFER_DESC_STS_SUCCESS USBH_LL_QTD_STATUS_SUCCESS
|
||||
#define USBH_HAL_XFER_DESC_STS_PKTERR USBH_LL_QTD_STATUS_PKTERR
|
||||
#define USBH_HAL_XFER_DESC_STS_BUFFER_ERR USBH_LL_QTD_STATUS_BUFFER
|
||||
#define USBH_HAL_XFER_DESC_STS_NOT_EXECUTED USBH_LL_QTD_STATUS_NOT_EXECUTED
|
||||
|
||||
// -------------------- Object Types -----------------------
|
||||
|
||||
/**
|
||||
* @brief Endpoint characteristics structure
|
||||
*/
|
||||
typedef struct {
|
||||
union {
|
||||
struct {
|
||||
usb_priv_xfer_type_t type: 2; /**< The type of endpoint */
|
||||
uint32_t bEndpointAddress: 8; /**< Endpoint address (containing endpoint number and direction) */
|
||||
uint32_t mps: 11; /**< Maximum Packet Size */
|
||||
uint32_t dev_addr: 8; /**< Device Address */
|
||||
uint32_t ls_via_fs_hub: 1; /**< The endpoint is on a LS device that is routed through an FS hub.
|
||||
Setting this bit will lead to the addition of the PREamble packet */
|
||||
uint32_t reserved2: 2;
|
||||
};
|
||||
uint32_t val;
|
||||
};
|
||||
struct {
|
||||
usb_hal_interval_t interval; /**< The interval of the endpoint */
|
||||
uint32_t phase_offset_frames; /**< Phase offset in number of frames */
|
||||
} periodic; /**< Characteristic for periodic (interrupt/isochronous) endpoints only */
|
||||
} usbh_hal_ep_char_t;
|
||||
|
||||
/**
|
||||
* @brief Channel object
|
||||
*/
|
||||
typedef struct {
|
||||
//Channel control, status, and information
|
||||
union {
|
||||
struct {
|
||||
uint32_t active: 1; /**< The channel is enabled */
|
||||
uint32_t halt_requested: 1; /**< A halt has been requested */
|
||||
uint32_t error_pending: 1; /**< The channel is waiting for the error to be handled */
|
||||
uint32_t reserved: 1;
|
||||
uint32_t chan_idx: 4; /**< The index number of the channel */
|
||||
uint32_t reserved24: 24;
|
||||
};
|
||||
uint32_t val;
|
||||
} flags; /**< Flags regarding channel's status and information */
|
||||
usb_host_chan_regs_t *regs; /**< Pointer to the channel's register set */
|
||||
usbh_hal_chan_error_t error; /**< The last error that occurred on the channel */
|
||||
usb_priv_xfer_type_t type; /**< The transfer type of the channel */
|
||||
void *chan_ctx; /**< Context variable for the owner of the channel */
|
||||
} usbh_hal_chan_t;
|
||||
|
||||
/**
|
||||
* @brief HAL context structure
|
||||
*/
|
||||
typedef struct {
|
||||
//Context
|
||||
usbh_dev_t *dev; /**< Pointer to base address of DWC_OTG registers */
|
||||
usb_wrap_dev_t *wrap_dev; /**< Pointer to base address of USB Wrapper registers */
|
||||
//Host Port related
|
||||
uint32_t *periodic_frame_list; /**< Pointer to scheduling frame list */
|
||||
usb_hal_frame_list_len_t frame_list_len; /**< Length of the periodic scheduling frame list */
|
||||
union {
|
||||
struct {
|
||||
uint32_t dbnc_lock_enabled: 1; /**< Debounce lock enabled */
|
||||
uint32_t fifo_sizes_set: 1; /**< Whether the FIFO sizes have been set or not */
|
||||
uint32_t periodic_sched_enabled: 1; /**< Periodic scheduling (for interrupt and isochronous transfers) is enabled */
|
||||
uint32_t reserved: 5;
|
||||
uint32_t reserved24: 24;
|
||||
};
|
||||
uint32_t val;
|
||||
} flags;
|
||||
//Channel related
|
||||
struct {
|
||||
int num_allocd; /**< Number of channels currently allocated */
|
||||
uint32_t chan_pend_intrs_msk; /**< Bit mask of channels with pending interrupts */
|
||||
usbh_hal_chan_t *hdls[USBH_HAL_NUM_CHAN]; /**< Handles of each channel. Set to NULL if channel has not been allocated */
|
||||
} channels;
|
||||
} usbh_hal_context_t;
|
||||
|
||||
// -------------------------------------------------- Core (Global) ----------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Initialize the HAL context and check if DWC_OTG is alive
|
||||
*
|
||||
* Entry:
|
||||
* - The peripheral must have been reset and clock un-gated
|
||||
* - GPIO pins configured
|
||||
* - Interrupt allocated but DISABLED (in case of an unknown interupt state)
|
||||
* Exit:
|
||||
* - Checks to see if DWC_OTG is alive, and if HW version/config is correct
|
||||
* - HAl context initialized
|
||||
* - Sets default values to some global and OTG registers (GAHBCFG and GUSBCFG)
|
||||
* - Umask global interrupt signal
|
||||
* - Put DWC_OTG into host mode. Require 25ms delay before this takes effect.
|
||||
* - State -> USBH_HAL_PORT_STATE_OTG
|
||||
* - Interrupts cleared. Users can now enable their ISR
|
||||
*
|
||||
* @param[inout] hal Context of the HAL layer
|
||||
*/
|
||||
void usbh_hal_init(usbh_hal_context_t *hal);
|
||||
|
||||
/**
|
||||
* @brief Deinitialize the HAL context
|
||||
*
|
||||
* Entry:
|
||||
* - All channels must be properly disabled, and any pending events handled
|
||||
* Exit:
|
||||
* - DWC_OTG global interrupt disabled
|
||||
* - HAL context deinitialized
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
*/
|
||||
void usbh_hal_deinit(usbh_hal_context_t *hal);
|
||||
|
||||
/**
|
||||
* @brief Issue a soft reset to the controller
|
||||
*
|
||||
* This should be called when the host port encounters an error event or has been disconnected. Before calling this,
|
||||
* users are responsible for safely freeing all channels as a soft reset will wipe all host port and channel registers.
|
||||
* This function will result in the host port being put back into same state as after calling usbh_hal_init().
|
||||
*
|
||||
* @note This has nothing to do with a USB bus reset. It simply resets the peripheral
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
*/
|
||||
void usbh_hal_core_soft_reset(usbh_hal_context_t *hal);
|
||||
|
||||
/**
|
||||
* @brief Set FIFO sizes
|
||||
*
|
||||
* This function will set the sizes of each of the FIFOs (RX FIFO, Non-periodic TX FIFO, Periodic TX FIFO) and must be
|
||||
* called at least once before allocating the channel. Based on the type of endpoints (and the endpionts' MPS), there
|
||||
* may be situations where this function may need to be called again to resize the FIFOs. If resizing FIFOs dynamically,
|
||||
* it is the user's responsibility to ensure there are no active channels when this function is called.
|
||||
*
|
||||
* @note The totol size of all the FIFOs must be less than or equal to USBH_HAL_FIFO_TOTAL_USABLE_LINES
|
||||
* @note After a port reset, the FIFO size registers will reset to their default values, so this function must be called
|
||||
* again post reset.
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
* @param fifo_config FIFO configuration
|
||||
*/
|
||||
void usbh_hal_set_fifo_size(usbh_hal_context_t *hal, const usbh_hal_fifo_config_t *fifo_config);
|
||||
|
||||
// ---------------------------------------------------- Host Port ------------------------------------------------------
|
||||
|
||||
// ------------------ Host Port Control --------------------
|
||||
|
||||
/**
|
||||
* @brief Initialize the host port
|
||||
*
|
||||
* - Will enable the host port's interrupts allowing port and channel events to occur
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
*/
|
||||
static inline void usbh_hal_port_init(usbh_hal_context_t *hal)
|
||||
{
|
||||
//Configure Host related interrupts
|
||||
usbh_ll_haintmsk_dis_chan_intr(hal->dev, 0xFFFFFFFF); //Disable interrupts for all channels
|
||||
usb_ll_en_intrs(hal->dev, USB_LL_INTR_CORE_PRTINT | USB_LL_INTR_CORE_HCHINT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deinitialize the host port
|
||||
*
|
||||
* - Will disable the host port's interrupts preventing further port aand channel events from ocurring
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
*/
|
||||
static inline void usbh_hal_port_deinit(usbh_hal_context_t *hal)
|
||||
{
|
||||
//Disable Host port and channel interrupts
|
||||
usb_ll_dis_intrs(hal->dev, USB_LL_INTR_CORE_PRTINT | USB_LL_INTR_CORE_HCHINT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Toggle the host port's power
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
* @param power_on Whether to power ON or OFF the port
|
||||
*/
|
||||
static inline void usbh_hal_port_toggle_power(usbh_hal_context_t *hal, bool power_on)
|
||||
{
|
||||
if (power_on) {
|
||||
usbh_ll_hprt_en_pwr(hal->dev);
|
||||
} else {
|
||||
usbh_ll_hprt_dis_pwr(hal->dev);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Toggle reset signal on the bus
|
||||
*
|
||||
* The reset signal should be held for at least 10ms
|
||||
* Entry:
|
||||
* - Host port detects a device connection or Host port is already enabled
|
||||
* Exit:
|
||||
* - On release of the reset signal, a USBH_HAL_PORT_EVENT_ENABLED will be generated
|
||||
*
|
||||
* @note If the host port is already enabled, then issuing a reset will cause it be disabled and generate a
|
||||
* USBH_HAL_PORT_EVENT_DISABLED event. The host port will not be enabled until the reset signal is released (thus
|
||||
* generating the USBH_HAL_PORT_EVENT_ENABLED event)
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
* @param enable Enable/disable reset signal
|
||||
*/
|
||||
static inline void usbh_hal_port_toggle_reset(usbh_hal_context_t *hal, bool enable)
|
||||
{
|
||||
assert(hal->channels.num_allocd == 0); //Cannot reset if there are still allocated channels
|
||||
usbh_ll_hprt_set_port_reset(hal->dev, enable);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable the host port
|
||||
*
|
||||
* Entry:
|
||||
* - Host port enabled event triggered following a reset
|
||||
* Exit:
|
||||
* - Host port enabled to operate in scatter/gather DMA mode
|
||||
* - DMA fifo sizes configured
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
*/
|
||||
void usbh_hal_port_enable(usbh_hal_context_t *hal);
|
||||
|
||||
/**
|
||||
* @brief Disable the host port
|
||||
*
|
||||
* Exit:
|
||||
* - Host port disabled event triggered
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
*/
|
||||
static inline void usbh_hal_port_disable(usbh_hal_context_t *hal)
|
||||
{
|
||||
usbh_ll_hprt_port_dis(hal->dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Suspend the host port
|
||||
*
|
||||
* @param hal Context of the HAL layers
|
||||
*/
|
||||
static inline void usbh_hal_port_suspend(usbh_hal_context_t *hal)
|
||||
{
|
||||
usbh_ll_hprt_set_port_suspend(hal->dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Toggle resume signal on the bus
|
||||
*
|
||||
* Hosts should hold the resume signal for at least 20ms
|
||||
*
|
||||
* @note If a remote wakeup event occurs, the resume signal is driven and cleared automatically.
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
* @param enable Enable/disable resume signal
|
||||
*/
|
||||
static inline void usbh_hal_port_toggle_resume(usbh_hal_context_t *hal, bool enable)
|
||||
{
|
||||
if (enable) {
|
||||
usbh_ll_hprt_set_port_resume(hal->dev);
|
||||
} else {
|
||||
usbh_ll_hprt_clr_port_resume(hal->dev);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check whether the resume signal is being driven
|
||||
*
|
||||
* If a remote wakeup event occurs, the core will automatically drive and clear the resume signal for the required
|
||||
* amount of time. Call this function to check whether the resume signal has completed.
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
* @return true Resume signal is still being driven
|
||||
* @return false Resume signal is no longer driven
|
||||
*/
|
||||
static inline bool usbh_hal_port_check_resume(usbh_hal_context_t *hal)
|
||||
{
|
||||
return usbh_ll_hprt_get_port_resume(hal->dev);
|
||||
}
|
||||
|
||||
// ---------------- Host Port Scheduling -------------------
|
||||
|
||||
/**
|
||||
* @brief Sets the periodic scheduling frame list
|
||||
*
|
||||
* @note This function must be called before attempting configuring any channels to be period via
|
||||
* usbh_hal_chan_set_ep_char()
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
* @param frame_list Base address of the frame list
|
||||
* @param frame_list_len Number of entries in the frame list (can only be 8, 16, 32, 64)
|
||||
*/
|
||||
static inline void usbh_hal_port_set_frame_list(usbh_hal_context_t *hal, uint32_t *frame_list, usb_hal_frame_list_len_t len)
|
||||
{
|
||||
assert(!hal->flags.periodic_sched_enabled);
|
||||
//Clear and save frame list
|
||||
hal->periodic_frame_list = frame_list;
|
||||
hal->frame_list_len = len;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the pointer to the periodic scheduling frame list
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
* @return uint32_t* Base address of the periodic scheduling frame list
|
||||
*/
|
||||
static inline uint32_t *usbh_hal_port_get_frame_list(usbh_hal_context_t *hal)
|
||||
{
|
||||
return hal->periodic_frame_list;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable periodic scheduling
|
||||
*
|
||||
* @note The periodic frame list must be set via usbh_hal_port_set_frame_list() should be set before calling this
|
||||
* function
|
||||
* @note This function must be called before activating any periodic channels
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
*/
|
||||
static inline void usbh_hal_port_periodic_enable(usbh_hal_context_t *hal)
|
||||
{
|
||||
assert(hal->periodic_frame_list != NULL && !hal->flags.periodic_sched_enabled);
|
||||
usbh_ll_set_frame_list_base_addr(hal->dev, (uint32_t)hal->periodic_frame_list);
|
||||
usbh_ll_hcfg_set_num_frame_list_entries(hal->dev, hal->frame_list_len);
|
||||
usbh_ll_hcfg_en_perio_sched(hal->dev);
|
||||
hal->flags.periodic_sched_enabled = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable periodic scheduling
|
||||
*
|
||||
* Disabling periodic scheduling will save a bit of DMA bandwith (as the controller will no longer fetch the schedule
|
||||
* from the frame list).
|
||||
*
|
||||
* @note Before disabling periodic scheduling, it is the user's responsibility to ensure that all periodic channels have
|
||||
* halted safely.
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
*/
|
||||
static inline void usbh_hal_port_periodic_disable(usbh_hal_context_t *hal)
|
||||
{
|
||||
assert(hal->flags.periodic_sched_enabled);
|
||||
usbh_ll_hcfg_dis_perio_sched(hal->dev);
|
||||
hal->flags.periodic_sched_enabled = 0;
|
||||
}
|
||||
|
||||
static inline uint32_t usbh_hal_port_get_cur_frame_num(usbh_hal_context_t *hal)
|
||||
{
|
||||
return usbh_ll_get_frm_num(hal->dev);
|
||||
}
|
||||
|
||||
// --------------- Host Port Status/State ------------------
|
||||
|
||||
/**
|
||||
* @brief Check if a device is currently connected to the host port
|
||||
*
|
||||
* This function is intended to be called after one of the following events followed by an adequate debounce delay
|
||||
* - USBH_HAL_PORT_EVENT_CONN
|
||||
* - USBH_HAL_PORT_EVENT_DISCONN
|
||||
*
|
||||
* @note No other connection/disconnection event will occur again until the debounce lock is disabled via
|
||||
* usbh_hal_disable_debounce_lock()
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
* @return true A device is connected to the host port
|
||||
* @return false A device is not connected to the host port
|
||||
*/
|
||||
static inline bool usbh_hal_port_check_if_connected(usbh_hal_context_t *hal)
|
||||
{
|
||||
return usbh_ll_hprt_get_conn_status(hal->dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check the speed (LS/FS) of the device connected to the host port
|
||||
*
|
||||
* @note This function should only be called after confirming that a device is connected to the host port
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
* @return usb_priv_speed_t Speed of the connected device (FS or LS only on the esp32-s2 and esp32-s3)
|
||||
*/
|
||||
static inline usb_priv_speed_t usbh_hal_port_get_conn_speed(usbh_hal_context_t *hal)
|
||||
{
|
||||
return usbh_ll_hprt_get_speed(hal->dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable the debounce lock
|
||||
*
|
||||
* This function must be called after calling usbh_hal_port_check_if_connected() and will allow connection/disconnection
|
||||
* events to occur again. Any pending connection or disconenction interrupts are cleared.
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
*/
|
||||
static inline void usbh_hal_disable_debounce_lock(usbh_hal_context_t *hal)
|
||||
{
|
||||
hal->flags.dbnc_lock_enabled = 0;
|
||||
//Clear Conenction and disconenction interrupt in case it triggered again
|
||||
usb_ll_intr_clear(hal->dev, USB_LL_INTR_CORE_DISCONNINT);
|
||||
usbh_ll_hprt_intr_clear(hal->dev, USBH_LL_INTR_HPRT_PRTENCHNG);
|
||||
//Reenable the hprt (connection) and disconnection interrupts
|
||||
usb_ll_en_intrs(hal->dev, USB_LL_INTR_CORE_PRTINT | USB_LL_INTR_CORE_DISCONNINT);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------- Channel -------------------------------------------------------
|
||||
|
||||
// ----------------- Channel Allocation --------------------
|
||||
|
||||
/**
|
||||
* @brief Allocate a channel
|
||||
*
|
||||
* @param[in] hal Context of the HAL layer
|
||||
* @param[inout] chan_obj Empty channel object
|
||||
* @param[in] chan_ctx Context variable for the allocator of the channel
|
||||
* @return true Channel successfully allocated
|
||||
* @return false Failed to allocate channel
|
||||
*/
|
||||
bool usbh_hal_chan_alloc(usbh_hal_context_t *hal, usbh_hal_chan_t *chan_obj, void *chan_ctx);
|
||||
|
||||
/**
|
||||
* @brief Free a channel
|
||||
*
|
||||
* @param[in] hal Context of the HAL layer
|
||||
* @param[in] chan_obj Channel object
|
||||
*/
|
||||
void usbh_hal_chan_free(usbh_hal_context_t *hal, usbh_hal_chan_t *chan_obj);
|
||||
|
||||
// ---------------- Channel Configuration ------------------
|
||||
|
||||
/**
|
||||
* @brief Get the context variable of the channel
|
||||
*
|
||||
* @param[in] chan_obj Channel object
|
||||
* @return void* The context variable of the channel
|
||||
*/
|
||||
static inline void *usbh_hal_chan_get_context(usbh_hal_chan_t *chan_obj)
|
||||
{
|
||||
return chan_obj->chan_ctx;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the current state of a channel
|
||||
*
|
||||
* @param chan_obj Channel object
|
||||
* @return usbh_hal_chan_state_t State of the channel
|
||||
*/
|
||||
static inline usbh_hal_chan_state_t usbh_hal_chan_get_state(usbh_hal_chan_t *chan_obj)
|
||||
{
|
||||
if (chan_obj->flags.error_pending) {
|
||||
return USBH_HAL_CHAN_STATE_ERROR;
|
||||
} else if (chan_obj->flags.active) {
|
||||
return USBH_HAL_CHAN_STATE_ACTIVE;
|
||||
} else {
|
||||
return USBH_HAL_CHAN_STATE_HALTED;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the endpoint information for a particular channel
|
||||
*
|
||||
* This should be called when a channel switches target from one EP to another
|
||||
*
|
||||
* @note the channel must be in the disabled state in order to change its EP
|
||||
* information
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
* @param chan_obj Channel object
|
||||
* @param ep_char Endpoint characteristics
|
||||
*/
|
||||
void usbh_hal_chan_set_ep_char(usbh_hal_context_t *hal, usbh_hal_chan_t *chan_obj, usbh_hal_ep_char_t *ep_char);
|
||||
|
||||
/**
|
||||
* @brief Set the direction of the channel
|
||||
*
|
||||
* This is a convenience function to flip the direction of a channel without
|
||||
* needing to reconfigure all of the channel's EP info. This is used primarily
|
||||
* for control transfers.
|
||||
*
|
||||
* @note This function should only be called when the channel is halted
|
||||
*
|
||||
* @param chan_obj Channel object
|
||||
* @param is_in Whether the direction is IN
|
||||
*/
|
||||
static inline void usbh_hal_chan_set_dir(usbh_hal_chan_t *chan_obj, bool is_in)
|
||||
{
|
||||
//Cannot change direction whilst channel is still active or in error
|
||||
assert(!chan_obj->flags.active && !chan_obj->flags.error_pending);
|
||||
usbh_ll_chan_set_dir(chan_obj->regs, is_in);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the next Packet ID of the channel (e.g., DATA0/DATA1)
|
||||
*
|
||||
* This should be called when a channel switches target from one EP to another
|
||||
* or when change stages for a control transfer
|
||||
*
|
||||
* @note The channel should only be called when the channel is in the
|
||||
* halted state.
|
||||
*
|
||||
* @param chan_obj Channel object
|
||||
* @param pid PID of the next DATA packet (DATA0 or DATA1)
|
||||
*/
|
||||
static inline void usbh_hal_chan_set_pid(usbh_hal_chan_t *chan_obj, int pid)
|
||||
{
|
||||
//Cannot change pid whilst channel is still active or in error
|
||||
assert(!chan_obj->flags.active && !chan_obj->flags.error_pending);
|
||||
//Update channel object and set the register
|
||||
usbh_ll_chan_set_pid(chan_obj->regs, pid);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the next PID of a channel
|
||||
*
|
||||
* Returns the next PID (DATA0 or DATA1) of the channel. This function should be
|
||||
* used when the next PID of a pipe needs to be saved (e.g., when switching pipes
|
||||
* on a channel)
|
||||
*
|
||||
* @param chan_obj Channel object
|
||||
* @return uint32_t Starting PID of the next transfer (DATA0 or DATA1)
|
||||
*/
|
||||
static inline uint32_t usbh_hal_chan_get_pid(usbh_hal_chan_t *chan_obj)
|
||||
{
|
||||
assert(!chan_obj->flags.active && !chan_obj->flags.error_pending);
|
||||
return usbh_ll_chan_get_pid(chan_obj->regs);
|
||||
}
|
||||
|
||||
// ------------------- Channel Control ---------------------
|
||||
|
||||
/**
|
||||
* @brief Activate a channel
|
||||
*
|
||||
* Activating a channel will cause the channel to start executing transfer descriptors.
|
||||
*
|
||||
* @note This function should only be called on channels that were previously halted
|
||||
* @note An event will be generated when the channel is halted
|
||||
*
|
||||
* @param chan_obj Channel object
|
||||
* @param xfer_desc_list A filled transfer descriptor list
|
||||
* @param desc_list_len Transfer descriptor list length
|
||||
* @param start_idx Index of the starting transfer descriptor in the list
|
||||
*/
|
||||
void usbh_hal_chan_activate(usbh_hal_chan_t *chan_obj, void *xfer_desc_list, int desc_list_len, int start_idx);
|
||||
|
||||
/**
|
||||
* @brief Get the index of the current transfer descriptor
|
||||
*
|
||||
* @param chan_obj Channel object
|
||||
* @return int Descriptor index
|
||||
*/
|
||||
static inline int usbh_hal_chan_get_qtd_idx(usbh_hal_chan_t *chan_obj)
|
||||
{
|
||||
return usbh_ll_chan_get_ctd(chan_obj->regs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Request to halt a channel
|
||||
*
|
||||
* This function should be called in order to halt a channel. If the channel is already halted, this function will
|
||||
* return true. If the channel is still active, this function will return false and users must wait for the
|
||||
* USBH_HAL_CHAN_EVENT_HALT_REQ event before treating the channel as halted.
|
||||
*
|
||||
* @note When a transfer is in progress (i.e., the channel is active) and a halt is requested, the channel will halt
|
||||
* after the next USB packet is completed. If the transfer has more pending packets, the transfer will just be
|
||||
* marked as USBH_HAL_XFER_DESC_STS_NOT_EXECUTED.
|
||||
*
|
||||
* @param chan_obj Channel object
|
||||
* @return true The channel is already halted
|
||||
* @return false The halt was requested, wait for USBH_HAL_CHAN_EVENT_HALT_REQ
|
||||
*/
|
||||
bool usbh_hal_chan_request_halt(usbh_hal_chan_t *chan_obj);
|
||||
|
||||
/**
|
||||
* @brief Get a channel's error
|
||||
*
|
||||
* @param chan_obj Channel object
|
||||
* @return usbh_hal_chan_error_t The type of error the channel has encountered
|
||||
*/
|
||||
static inline usbh_hal_chan_error_t usbh_hal_chan_get_error(usbh_hal_chan_t *chan_obj)
|
||||
{
|
||||
assert(chan_obj->flags.error_pending);
|
||||
return chan_obj->error;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clear a channel of it's error
|
||||
*
|
||||
* @param chan_obj Channel object
|
||||
*/
|
||||
static inline void usbh_hal_chan_clear_error(usbh_hal_chan_t *chan_obj)
|
||||
{
|
||||
//Can only clear error when an error has occurred
|
||||
assert(chan_obj->flags.error_pending);
|
||||
chan_obj->flags.error_pending = 0;
|
||||
}
|
||||
|
||||
// -------------------------------------------- Transfer Descriptor List -----------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Fill a single entry in a transfer descriptor list
|
||||
*
|
||||
* - Depending on the transfer type, a single transfer descriptor may corresponds
|
||||
* - A stage of a transfer (for control transfers)
|
||||
* - A frame of a transfer interval (for interrupt and isoc)
|
||||
* - An entire transfer (for bulk transfers)
|
||||
* - Check the various USBH_HAL_XFER_DESC_FLAG_ flags for filling a specific type of descriptor
|
||||
* - For IN transfer entries, set the USBH_HAL_XFER_DESC_FLAG_IN. The transfer size must also be an integer multiple of
|
||||
* the endpoint's MPS
|
||||
*
|
||||
* @note Critical section is not required for this function
|
||||
*
|
||||
* @param desc_list Transfer descriptor list
|
||||
* @param desc_idx Transfer descriptor index
|
||||
* @param xfer_data_buff Transfer data buffer
|
||||
* @param xfer_len Transfer length
|
||||
* @param flags Transfer flags
|
||||
*/
|
||||
static inline void usbh_hal_xfer_desc_fill(void *desc_list, uint32_t desc_idx, uint8_t *xfer_data_buff, int xfer_len, uint32_t flags)
|
||||
{
|
||||
usbh_ll_dma_qtd_t *qtd_list = (usbh_ll_dma_qtd_t *)desc_list;
|
||||
if (flags & USBH_HAL_XFER_DESC_FLAG_IN) {
|
||||
usbh_ll_set_qtd_in(&qtd_list[desc_idx],
|
||||
xfer_data_buff, xfer_len,
|
||||
flags & USBH_HAL_XFER_DESC_FLAG_HOC);
|
||||
} else {
|
||||
usbh_ll_set_qtd_out(&qtd_list[desc_idx],
|
||||
xfer_data_buff,
|
||||
xfer_len,
|
||||
flags & USBH_HAL_XFER_DESC_FLAG_HOC,
|
||||
flags & USBH_HAL_XFER_DESC_FLAG_SETUP);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clear a transfer descriptor (sets all its fields to NULL)
|
||||
*
|
||||
* @param desc_list Transfer descriptor list
|
||||
* @param desc_idx Transfer descriptor index
|
||||
*/
|
||||
static inline void usbh_hal_xfer_desc_clear(void *desc_list, uint32_t desc_idx)
|
||||
{
|
||||
usbh_ll_dma_qtd_t *qtd_list = (usbh_ll_dma_qtd_t *)desc_list;
|
||||
usbh_ll_set_qtd_null(&qtd_list[desc_idx]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Parse a transfer decriptor's results
|
||||
*
|
||||
* @param desc_list Transfer descriptor list
|
||||
* @param desc_idx Transfer descriptor index
|
||||
* @param[out] xfer_rem_len Remaining length of the transfer in bytes
|
||||
* @param[out] xfer_status Status of the transfer
|
||||
*
|
||||
* @note Critical section is not required for this function
|
||||
*/
|
||||
static inline void usbh_hal_xfer_desc_parse(void *desc_list, uint32_t desc_idx, int *xfer_rem_len, int *xfer_status)
|
||||
{
|
||||
usbh_ll_dma_qtd_t *qtd_list = (usbh_ll_dma_qtd_t *)desc_list;
|
||||
usbh_ll_get_qtd_status(&qtd_list[desc_idx], xfer_rem_len, xfer_status);
|
||||
//Clear the QTD to prevent it from being read again
|
||||
usbh_ll_set_qtd_null(&qtd_list[desc_idx]);
|
||||
}
|
||||
|
||||
// ------------------------------------------------- Event Handling ----------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Decode global and host port interrupts
|
||||
*
|
||||
* - Reads and clears global and host port interrupt registers
|
||||
* - Decodes the interrupt bits to determine what host port event occurred
|
||||
*
|
||||
* @note This should be the first interrupt decode function to be run
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
* @return usbh_hal_port_event_t Host port event
|
||||
*/
|
||||
usbh_hal_port_event_t usbh_hal_decode_intr(usbh_hal_context_t *hal);
|
||||
|
||||
/**
|
||||
* @brief Gets the next channel with a pending interrupt
|
||||
*
|
||||
* If no channel is pending an interrupt, this function will return NULL. If one or more channels are pending an
|
||||
* interrupt, this function returns one of the channel's objects. Call this function repeatedly until it returns NULL.
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
* @return usbh_hal_chan_t* Channel object. NULL if no channel are pending an interrupt.
|
||||
*/
|
||||
usbh_hal_chan_t *usbh_hal_get_chan_pending_intr(usbh_hal_context_t *hal);
|
||||
|
||||
/**
|
||||
* @brief Decode a particular channel's interrupt
|
||||
*
|
||||
* - Reads and clears the interrupt register of the channel
|
||||
* - Returns the corresponding event for that channel
|
||||
*
|
||||
* @param chan_obj Channel object
|
||||
* @return usbh_hal_chan_event_t Channel event
|
||||
*/
|
||||
usbh_hal_chan_event_t usbh_hal_chan_decode_intr(usbh_hal_chan_t *chan_obj);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
980
tools/sdk/esp32/include/hal/include/hal/usbh_ll.h
Normal file
980
tools/sdk/esp32/include/hal/include/hal/usbh_ll.h
Normal file
@ -0,0 +1,980 @@
|
||||
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "soc/usbh_struct.h"
|
||||
#include "soc/usb_wrap_struct.h"
|
||||
#include "hal/usb_types_private.h"
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
------------------------------- Global Registers -------------------------------
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Interrupt bit masks of the GINTSTS and GINTMSK registers
|
||||
*/
|
||||
#define USB_LL_INTR_CORE_WKUPINT (1 << 31)
|
||||
#define USB_LL_INTR_CORE_SESSREQINT (1 << 30)
|
||||
#define USB_LL_INTR_CORE_DISCONNINT (1 << 29)
|
||||
#define USB_LL_INTR_CORE_CONIDSTSCHNG (1 << 28)
|
||||
#define USB_LL_INTR_CORE_PTXFEMP (1 << 26)
|
||||
#define USB_LL_INTR_CORE_HCHINT (1 << 25)
|
||||
#define USB_LL_INTR_CORE_PRTINT (1 << 24)
|
||||
#define USB_LL_INTR_CORE_RESETDET (1 << 23)
|
||||
#define USB_LL_INTR_CORE_FETSUSP (1 << 22)
|
||||
#define USB_LL_INTR_CORE_INCOMPIP (1 << 21)
|
||||
#define USB_LL_INTR_CORE_INCOMPISOIN (1 << 20)
|
||||
#define USB_LL_INTR_CORE_OEPINT (1 << 19)
|
||||
#define USB_LL_INTR_CORE_IEPINT (1 << 18)
|
||||
#define USB_LL_INTR_CORE_EPMIS (1 << 17)
|
||||
#define USB_LL_INTR_CORE_EOPF (1 << 15)
|
||||
#define USB_LL_INTR_CORE_ISOOUTDROP (1 << 14)
|
||||
#define USB_LL_INTR_CORE_ENUMDONE (1 << 13)
|
||||
#define USB_LL_INTR_CORE_USBRST (1 << 12)
|
||||
#define USB_LL_INTR_CORE_USBSUSP (1 << 11)
|
||||
#define USB_LL_INTR_CORE_ERLYSUSP (1 << 10)
|
||||
#define USB_LL_INTR_CORE_GOUTNAKEFF (1 << 7)
|
||||
#define USB_LL_INTR_CORE_GINNAKEFF (1 << 6)
|
||||
#define USB_LL_INTR_CORE_NPTXFEMP (1 << 5)
|
||||
#define USB_LL_INTR_CORE_RXFLVL (1 << 4)
|
||||
#define USB_LL_INTR_CORE_SOF (1 << 3)
|
||||
#define USB_LL_INTR_CORE_OTGINT (1 << 2)
|
||||
#define USB_LL_INTR_CORE_MODEMIS (1 << 1)
|
||||
#define USB_LL_INTR_CORE_CURMOD (1 << 0)
|
||||
|
||||
/*
|
||||
* Bit mask of interrupt generating bits of the the HPRT register. These bits
|
||||
* are ORd into the USB_LL_INTR_CORE_PRTINT interrupt.
|
||||
*
|
||||
* Note: Some fields of the HPRT are W1C (write 1 clear), this we cannot do a
|
||||
* simple read and write-back to clear the HPRT interrupt bits. Instead we need
|
||||
* a W1C mask the non-interrupt related bits
|
||||
*/
|
||||
#define USBH_LL_HPRT_W1C_MSK (0x2E)
|
||||
#define USBH_LL_HPRT_ENA_MSK (0x04)
|
||||
#define USBH_LL_INTR_HPRT_PRTOVRCURRCHNG (1 << 5)
|
||||
#define USBH_LL_INTR_HPRT_PRTENCHNG (1 << 3)
|
||||
#define USBH_LL_INTR_HPRT_PRTCONNDET (1 << 1)
|
||||
|
||||
/*
|
||||
* Bit mask of channel interrupts (HCINTi and HCINTMSKi registers)
|
||||
*
|
||||
* Note: Under Scatter/Gather DMA mode, only the following interrupts can be unmasked
|
||||
* - DESC_LS_ROLL
|
||||
* - XCS_XACT_ERR (always unmasked)
|
||||
* - BNAINTR
|
||||
* - CHHLTD
|
||||
* - XFERCOMPL
|
||||
* The remaining interrupt bits will still be set (when the corresponding event occurs)
|
||||
* but will not generate an interrupt. Therefore we must proxy through the
|
||||
* USBH_LL_INTR_CHAN_CHHLTD interrupt to check the other interrupt bits.
|
||||
*/
|
||||
#define USBH_LL_INTR_CHAN_DESC_LS_ROLL (1 << 13)
|
||||
#define USBH_LL_INTR_CHAN_XCS_XACT_ERR (1 << 12)
|
||||
#define USBH_LL_INTR_CHAN_BNAINTR (1 << 11)
|
||||
#define USBH_LL_INTR_CHAN_DATATGLERR (1 << 10)
|
||||
#define USBH_LL_INTR_CHAN_FRMOVRUN (1 << 9)
|
||||
#define USBH_LL_INTR_CHAN_BBLEER (1 << 8)
|
||||
#define USBH_LL_INTR_CHAN_XACTERR (1 << 7)
|
||||
#define USBH_LL_INTR_CHAN_NYET (1 << 6)
|
||||
#define USBH_LL_INTR_CHAN_ACK (1 << 5)
|
||||
#define USBH_LL_INTR_CHAN_NAK (1 << 4)
|
||||
#define USBH_LL_INTR_CHAN_STALL (1 << 3)
|
||||
#define USBH_LL_INTR_CHAN_AHBERR (1 << 2)
|
||||
#define USBH_LL_INTR_CHAN_CHHLTD (1 << 1)
|
||||
#define USBH_LL_INTR_CHAN_XFERCOMPL (1 << 0)
|
||||
|
||||
/*
|
||||
* QTD (Queue Transfer Descriptor) structure used in Scatter/Gather DMA mode.
|
||||
* Each QTD describes one transfer. Scatter gather mode will automatically split
|
||||
* a transfer into multiple MPS packets. Each QTD is 64bits in size
|
||||
*
|
||||
* Note: The status information part of the QTD is interpreted differently depending
|
||||
* on IN or OUT, and ISO or non-ISO
|
||||
*/
|
||||
typedef struct {
|
||||
union {
|
||||
struct {
|
||||
uint32_t xfer_size: 17;
|
||||
uint32_t aqtd_offset: 6;
|
||||
uint32_t aqtd_valid: 1;
|
||||
uint32_t reserved_24: 1;
|
||||
uint32_t intr_cplt: 1;
|
||||
uint32_t eol: 1;
|
||||
uint32_t reserved_27: 1;
|
||||
uint32_t rx_status: 2;
|
||||
uint32_t reserved_30: 1;
|
||||
uint32_t active: 1;
|
||||
} in_non_iso;
|
||||
struct {
|
||||
uint32_t xfer_size: 12;
|
||||
uint32_t reserved_12_24: 13;
|
||||
uint32_t intr_cplt: 1;
|
||||
uint32_t reserved_26_27: 2;
|
||||
uint32_t rx_status: 2;
|
||||
uint32_t reserved_30: 1;
|
||||
uint32_t active: 1;
|
||||
} in_iso;
|
||||
struct {
|
||||
uint32_t xfer_size: 17;
|
||||
uint32_t reserved_17_23: 7;
|
||||
uint32_t is_setup: 1;
|
||||
uint32_t intr_cplt: 1;
|
||||
uint32_t eol: 1;
|
||||
uint32_t reserved_27: 1;
|
||||
uint32_t tx_status: 2;
|
||||
uint32_t reserved_30: 1;
|
||||
uint32_t active: 1;
|
||||
} out_non_iso;
|
||||
struct {
|
||||
uint32_t xfer_size: 12;
|
||||
uint32_t reserved_12_24: 13;
|
||||
uint32_t intr_cplt: 1;
|
||||
uint32_t eol: 1;
|
||||
uint32_t reserved_27: 1;
|
||||
uint32_t tx_status: 2;
|
||||
uint32_t reserved_30: 1;
|
||||
uint32_t active: 1;
|
||||
} out_iso;
|
||||
uint32_t buffer_status_val;
|
||||
};
|
||||
uint8_t *buffer;
|
||||
} usbh_ll_dma_qtd_t;
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
------------------------------ USB Wrap Registers ------------------------------
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* @brief Configures the internal PHY to operate as HOST
|
||||
*
|
||||
* @param hw Start address of the USB Wrap registers
|
||||
*/
|
||||
static inline void usbh_ll_internal_phy_conf(usb_wrap_dev_t *hw)
|
||||
{
|
||||
//Enable internal PHY
|
||||
hw->otg_conf.pad_enable = 1;
|
||||
hw->otg_conf.phy_sel = 0;
|
||||
//Set pulldowns on D+ and D-
|
||||
hw->otg_conf.pad_pull_override = 1;
|
||||
hw->otg_conf.dp_pulldown = 1;
|
||||
hw->otg_conf.dm_pulldown = 1;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
------------------------------- Global Registers -------------------------------
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
// --------------------------- GAHBCFG Register --------------------------------
|
||||
|
||||
static inline void usb_ll_en_dma_mode(usbh_dev_t *hw)
|
||||
{
|
||||
hw->gahbcfg_reg.dmaen = 1;
|
||||
}
|
||||
|
||||
static inline void usb_ll_en_slave_mode(usbh_dev_t *hw)
|
||||
{
|
||||
hw->gahbcfg_reg.dmaen = 0;
|
||||
}
|
||||
|
||||
static inline void usb_ll_set_hbstlen(usbh_dev_t *hw, uint32_t burst_len)
|
||||
{
|
||||
hw->gahbcfg_reg.hbstlen = burst_len;
|
||||
}
|
||||
|
||||
static inline void usb_ll_en_global_intr(usbh_dev_t *hw)
|
||||
{
|
||||
hw->gahbcfg_reg.glbllntrmsk = 1;
|
||||
}
|
||||
|
||||
static inline void usb_ll_dis_global_intr(usbh_dev_t *hw)
|
||||
{
|
||||
hw->gahbcfg_reg.glbllntrmsk = 0;
|
||||
}
|
||||
|
||||
// --------------------------- GUSBCFG Register --------------------------------
|
||||
|
||||
static inline void usb_ll_set_host_mode(usbh_dev_t *hw)
|
||||
{
|
||||
hw->gusbcfg_reg.forcehstmode = 1;
|
||||
}
|
||||
|
||||
static inline void usb_ll_dis_hnp_cap(usbh_dev_t *hw)
|
||||
{
|
||||
hw->gusbcfg_reg.hnpcap = 0;
|
||||
}
|
||||
|
||||
static inline void usb_ll_dis_srp_cap(usbh_dev_t *hw)
|
||||
{
|
||||
hw->gusbcfg_reg.srpcap = 0;
|
||||
}
|
||||
|
||||
// --------------------------- GRSTCTL Register --------------------------------
|
||||
|
||||
static inline bool usb_ll_check_ahb_idle(usbh_dev_t *hw)
|
||||
{
|
||||
return hw->grstctl_reg.ahbidle;
|
||||
}
|
||||
|
||||
static inline bool usb_ll_check_dma_req_in_progress(usbh_dev_t *hw)
|
||||
{
|
||||
return hw->grstctl_reg.dmareq;
|
||||
}
|
||||
|
||||
static inline void usb_ll_flush_nptx_fifo(usbh_dev_t *hw)
|
||||
{
|
||||
hw->grstctl_reg.txfnum = 0; //Set the TX FIFO number to 0 to select the non-periodic TX FIFO
|
||||
hw->grstctl_reg.txfflsh = 1; //Flush the selected TX FIFO
|
||||
//Wait for the flushing to complete
|
||||
while (hw->grstctl_reg.txfflsh) {
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void usb_ll_flush_ptx_fifo(usbh_dev_t *hw)
|
||||
{
|
||||
hw->grstctl_reg.txfnum = 1; //Set the TX FIFO number to 1 to select the periodic TX FIFO
|
||||
hw->grstctl_reg.txfflsh = 1; //FLush the select TX FIFO
|
||||
//Wait for the flushing to complete
|
||||
while (hw->grstctl_reg.txfflsh) {
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void usb_ll_flush_rx_fifo(usbh_dev_t *hw)
|
||||
{
|
||||
hw->grstctl_reg.rxfflsh = 1;
|
||||
//Wait for the flushing to complete
|
||||
while (hw->grstctl_reg.rxfflsh) {
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void usb_ll_reset_frame_counter(usbh_dev_t *hw)
|
||||
{
|
||||
hw->grstctl_reg.frmcntrrst = 1;
|
||||
}
|
||||
|
||||
static inline void usb_ll_core_soft_reset(usbh_dev_t *hw)
|
||||
{
|
||||
hw->grstctl_reg.csftrst = 1;
|
||||
}
|
||||
|
||||
static inline bool usb_ll_check_core_soft_reset(usbh_dev_t *hw)
|
||||
{
|
||||
return hw->grstctl_reg.csftrst;
|
||||
}
|
||||
|
||||
// --------------------------- GINTSTS Register --------------------------------
|
||||
|
||||
/**
|
||||
* @brief Reads and clears the global interrupt register
|
||||
*
|
||||
* @param hw Start address of the DWC_OTG registers
|
||||
* @return uint32_t Mask of interrupts
|
||||
*/
|
||||
static inline uint32_t usb_ll_intr_read_and_clear(usbh_dev_t *hw)
|
||||
{
|
||||
usb_gintsts_reg_t gintsts;
|
||||
gintsts.val = hw->gintsts_reg.val;
|
||||
hw->gintsts_reg.val = gintsts.val; //Write back to clear
|
||||
return gintsts.val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clear specific interrupts
|
||||
*
|
||||
* @param hw Start address of the DWC_OTG registers
|
||||
* @param intr_msk Mask of interrupts to clear
|
||||
*/
|
||||
static inline void usb_ll_intr_clear(usbh_dev_t *hw, uint32_t intr_msk)
|
||||
{
|
||||
//All GINTSTS fields are either W1C or read only. So safe to write directly
|
||||
hw->gintsts_reg.val = intr_msk;
|
||||
}
|
||||
|
||||
// --------------------------- GINTMSK Register --------------------------------
|
||||
|
||||
static inline void usb_ll_en_intrs(usbh_dev_t *hw, uint32_t intr_mask)
|
||||
{
|
||||
hw->gintmsk_reg.val |= intr_mask;
|
||||
}
|
||||
|
||||
static inline void usb_ll_dis_intrs(usbh_dev_t *hw, uint32_t intr_mask)
|
||||
{
|
||||
hw->gintmsk_reg.val &= ~intr_mask;
|
||||
}
|
||||
|
||||
// --------------------------- GRXFSIZ Register --------------------------------
|
||||
|
||||
static inline void usb_ll_set_rx_fifo_size(usbh_dev_t *hw, uint32_t num_lines)
|
||||
{
|
||||
//Set size in words
|
||||
hw->grxfsiz_reg.rxfdep = num_lines;
|
||||
}
|
||||
|
||||
// -------------------------- GNPTXFSIZ Register -------------------------------
|
||||
|
||||
static inline void usb_ll_set_nptx_fifo_size(usbh_dev_t *hw, uint32_t addr, uint32_t num_lines)
|
||||
{
|
||||
usb_gnptxfsiz_reg_t gnptxfsiz;
|
||||
gnptxfsiz.val = hw->gnptxfsiz_reg.val;
|
||||
gnptxfsiz.nptxfstaddr = addr;
|
||||
gnptxfsiz.nptxfdep = num_lines;
|
||||
hw->gnptxfsiz_reg.val = gnptxfsiz.val;
|
||||
}
|
||||
|
||||
static inline uint32_t usb_ll_get_controller_core_id(usbh_dev_t *hw)
|
||||
{
|
||||
return hw->gsnpsid_reg.val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the hardware configuration regiters of the DWC_OTG controller
|
||||
*
|
||||
* The hardware configuraiton regitsers are read only and indicate the various
|
||||
* features of the DWC_OTG core.
|
||||
*
|
||||
* @param hw Start address of the DWC_OTG registers
|
||||
* @param[out] ghwcfg1 Hardware configuration registesr 1
|
||||
* @param[out] ghwcfg2 Hardware configuration registesr 2
|
||||
* @param[out] ghwcfg3 Hardware configuration registesr 3
|
||||
* @param[out] ghwcfg4 Hardware configuration registesr 4
|
||||
*/
|
||||
static inline void usb_ll_get_hardware_config(usbh_dev_t *hw, uint32_t *ghwcfg1, uint32_t *ghwcfg2, uint32_t *ghwcfg3, uint32_t *ghwcfg4)
|
||||
{
|
||||
*ghwcfg1 = hw->ghwcfg1_reg.val;
|
||||
*ghwcfg2 = hw->ghwcfg2_reg.val;
|
||||
*ghwcfg3 = hw->ghwcfg3_reg.val;
|
||||
*ghwcfg4 = hw->ghwcfg4_reg.val;
|
||||
}
|
||||
|
||||
// --------------------------- HPTXFSIZ Register -------------------------------
|
||||
|
||||
static inline void usbh_ll_set_ptx_fifo_size(usbh_dev_t *hw, uint32_t addr, uint32_t num_lines)
|
||||
{
|
||||
usb_hptxfsiz_reg_t hptxfsiz;
|
||||
hptxfsiz.val = hw->hptxfsiz_reg.val;
|
||||
hptxfsiz.ptxfstaddr = addr;
|
||||
hptxfsiz.ptxfsize = num_lines;
|
||||
hw->hptxfsiz_reg.val = hptxfsiz.val;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
-------------------------------- Host Registers --------------------------------
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
// ----------------------------- HCFG Register ---------------------------------
|
||||
|
||||
static inline void usbh_ll_hcfg_en_perio_sched(usbh_dev_t *hw)
|
||||
{
|
||||
hw->hcfg_reg.perschedena = 1;
|
||||
}
|
||||
|
||||
static inline void usbh_ll_hcfg_dis_perio_sched(usbh_dev_t *hw)
|
||||
{
|
||||
hw->hcfg_reg.perschedena = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the length of the frame list
|
||||
*
|
||||
* @param num_entires Number of entires in the frame list
|
||||
*/
|
||||
static inline void usbh_ll_hcfg_set_num_frame_list_entries(usbh_dev_t *hw, usb_hal_frame_list_len_t num_entries)
|
||||
{
|
||||
uint32_t frlisten;
|
||||
switch (num_entries) {
|
||||
case USB_HAL_FRAME_LIST_LEN_8:
|
||||
frlisten = 0;
|
||||
break;
|
||||
case USB_HAL_FRAME_LIST_LEN_16:
|
||||
frlisten = 1;
|
||||
break;
|
||||
case USB_HAL_FRAME_LIST_LEN_32:
|
||||
frlisten = 2;
|
||||
break;
|
||||
default: //USB_HAL_FRAME_LIST_LEN_64
|
||||
frlisten = 3;
|
||||
break;
|
||||
}
|
||||
hw->hcfg_reg.frlisten = frlisten;
|
||||
}
|
||||
|
||||
static inline void usbh_ll_hcfg_en_scatt_gatt_dma(usbh_dev_t *hw)
|
||||
{
|
||||
hw->hcfg_reg.descdma = 1;
|
||||
}
|
||||
|
||||
static inline void usbh_ll_hcfg_set_fsls_supp_only(usbh_dev_t *hw)
|
||||
{
|
||||
hw->hcfg_reg.fslssupp = 1;
|
||||
}
|
||||
|
||||
static inline void usbh_ll_hcfg_set_fsls_pclk_sel(usbh_dev_t *hw)
|
||||
{
|
||||
hw->hcfg_reg.fslspclksel = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets some default values to HCFG to operate in Host mode with scatter/gather DMA
|
||||
*
|
||||
* @param hw Start address of the USB Wrap registers
|
||||
* @param speed Speed to initialize the host port at
|
||||
*/
|
||||
static inline void usbh_ll_hcfg_set_defaults(usbh_dev_t *hw, usb_priv_speed_t speed)
|
||||
{
|
||||
hw->hcfg_reg.descdma = 1; //Enable scatt/gatt
|
||||
hw->hcfg_reg.fslssupp = 1; //FS/LS support only
|
||||
/*
|
||||
Indicate to the OTG core what speed the PHY clock is at
|
||||
Note: It seems like our PHY has an implicit 8 divider applied when in LS mode,
|
||||
so the values of FSLSPclkSel and FrInt have to be adjusted accordingly.
|
||||
*/
|
||||
hw->hcfg_reg.fslspclksel = (speed == USB_PRIV_SPEED_FULL) ? 1 : 2; //PHY clock on esp32-sx for FS/LS-only
|
||||
hw->hcfg_reg.perschedena = 0; //Disable perio sched
|
||||
}
|
||||
|
||||
// ----------------------------- HFIR Register ---------------------------------
|
||||
|
||||
static inline void usbh_ll_hfir_set_defaults(usbh_dev_t *hw, usb_priv_speed_t speed)
|
||||
{
|
||||
usb_hfir_reg_t hfir;
|
||||
hfir.val = hw->hfir_reg.val;
|
||||
hfir.hfirrldctrl = 0; //Disable dynamic loading
|
||||
/*
|
||||
Set frame interval to be equal to 1ms
|
||||
Note: It seems like our PHY has an implicit 8 divider applied when in LS mode,
|
||||
so the values of FSLSPclkSel and FrInt have to be adjusted accordingly.
|
||||
*/
|
||||
hfir.frint = (speed == USB_PRIV_SPEED_FULL) ? 48000 : 6000; //esp32-sx targets only support FS or LS
|
||||
hw->hfir_reg.val = hfir.val;
|
||||
}
|
||||
|
||||
// ----------------------------- HFNUM Register --------------------------------
|
||||
|
||||
static inline uint32_t usbh_ll_get_frm_time_rem(usbh_dev_t *hw)
|
||||
{
|
||||
return hw->hfnum_reg.frrem;
|
||||
}
|
||||
|
||||
static inline uint32_t usbh_ll_get_frm_num(usbh_dev_t *hw)
|
||||
{
|
||||
return hw->hfnum_reg.frnum;
|
||||
}
|
||||
|
||||
// ---------------------------- HPTXSTS Register -------------------------------
|
||||
|
||||
static inline uint32_t usbh_ll_get_p_tx_queue_top(usbh_dev_t *hw)
|
||||
{
|
||||
return hw->hptxsts_reg.ptxqtop;
|
||||
}
|
||||
|
||||
static inline uint32_t usbh_ll_get_p_tx_queue_space_avail(usbh_dev_t *hw)
|
||||
{
|
||||
return hw->hptxsts_reg.ptxqspcavail;
|
||||
}
|
||||
|
||||
static inline uint32_t usbh_ll_get_p_tx_fifo_space_avail(usbh_dev_t *hw)
|
||||
{
|
||||
return hw->hptxsts_reg.ptxfspcavail;
|
||||
}
|
||||
|
||||
// ----------------------------- HAINT Register --------------------------------
|
||||
|
||||
static inline uint32_t usbh_ll_get_chan_intrs_msk(usbh_dev_t *hw)
|
||||
{
|
||||
return hw->haint_reg.haint;
|
||||
}
|
||||
|
||||
// --------------------------- HAINTMSK Register -------------------------------
|
||||
|
||||
static inline void usbh_ll_haintmsk_en_chan_intr(usbh_dev_t *hw, uint32_t mask)
|
||||
{
|
||||
hw->haintmsk_reg.val |= mask;
|
||||
}
|
||||
|
||||
static inline void usbh_ll_haintmsk_dis_chan_intr(usbh_dev_t *hw, uint32_t mask)
|
||||
{
|
||||
hw->haintmsk_reg.val &= ~mask;
|
||||
}
|
||||
|
||||
// --------------------------- HFLBAddr Register -------------------------------
|
||||
|
||||
/**
|
||||
* @brief Set the base address of the scheduling frame list
|
||||
*
|
||||
* @note For some reason, this address must be 512 bytes aligned or else a bunch of frames will not be scheduled when
|
||||
* the frame list rolls over. However, according to the databook, there is no mention of the HFLBAddr needing to
|
||||
* be aligned.
|
||||
*
|
||||
* @param hw Start address of the DWC_OTG registers
|
||||
* @param addr Base address of the scheduling frame list
|
||||
*/
|
||||
static inline void usbh_ll_set_frame_list_base_addr(usbh_dev_t *hw, uint32_t addr)
|
||||
{
|
||||
hw->hflbaddr_reg.hflbaddr = addr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the base address of the scheduling frame list
|
||||
*
|
||||
* @param hw Start address of the DWC_OTG registers
|
||||
* @return uint32_t Base address of the scheduling frame list
|
||||
*/
|
||||
static inline uint32_t usbh_ll_get_frame_list_base_addr(usbh_dev_t *hw)
|
||||
{
|
||||
return hw->hflbaddr_reg.hflbaddr;
|
||||
}
|
||||
|
||||
// ----------------------------- HPRT Register ---------------------------------
|
||||
|
||||
static inline usb_priv_speed_t usbh_ll_hprt_get_speed(usbh_dev_t *hw)
|
||||
{
|
||||
usb_priv_speed_t speed;
|
||||
//esp32-s2 and esp32-s3 only support FS or LS
|
||||
switch (hw->hprt_reg.prtspd) {
|
||||
case 1:
|
||||
speed = USB_PRIV_SPEED_FULL;
|
||||
break;
|
||||
default:
|
||||
speed = USB_PRIV_SPEED_LOW;
|
||||
break;
|
||||
}
|
||||
return speed;
|
||||
}
|
||||
|
||||
static inline uint32_t usbh_ll_hprt_get_test_ctl(usbh_dev_t *hw)
|
||||
{
|
||||
return hw->hprt_reg.prttstctl;
|
||||
}
|
||||
|
||||
static inline void usbh_ll_hprt_set_test_ctl(usbh_dev_t *hw, uint32_t test_mode)
|
||||
{
|
||||
usb_hprt_reg_t hprt;
|
||||
hprt.val = hw->hprt_reg.val;
|
||||
hprt.prttstctl = test_mode;
|
||||
hw->hprt_reg.val = hprt.val & (~USBH_LL_HPRT_W1C_MSK);
|
||||
}
|
||||
|
||||
static inline void usbh_ll_hprt_en_pwr(usbh_dev_t *hw)
|
||||
{
|
||||
usb_hprt_reg_t hprt;
|
||||
hprt.val = hw->hprt_reg.val;
|
||||
hprt.prtpwr = 1;
|
||||
hw->hprt_reg.val = hprt.val & (~USBH_LL_HPRT_W1C_MSK);
|
||||
}
|
||||
|
||||
static inline void usbh_ll_hprt_dis_pwr(usbh_dev_t *hw)
|
||||
{
|
||||
usb_hprt_reg_t hprt;
|
||||
hprt.val = hw->hprt_reg.val;
|
||||
hprt.prtpwr = 0;
|
||||
hw->hprt_reg.val = hprt.val & (~USBH_LL_HPRT_W1C_MSK);
|
||||
}
|
||||
|
||||
static inline uint32_t usbh_ll_hprt_get_pwr_line_status(usbh_dev_t *hw)
|
||||
{
|
||||
return hw->hprt_reg.prtlnsts;
|
||||
}
|
||||
|
||||
static inline void usbh_ll_hprt_set_port_reset(usbh_dev_t *hw, bool reset)
|
||||
{
|
||||
usb_hprt_reg_t hprt;
|
||||
hprt.val = hw->hprt_reg.val;
|
||||
hprt.prtrst = reset;
|
||||
hw->hprt_reg.val = hprt.val & (~USBH_LL_HPRT_W1C_MSK);
|
||||
}
|
||||
|
||||
static inline bool usbh_ll_hprt_get_port_reset(usbh_dev_t *hw)
|
||||
{
|
||||
return hw->hprt_reg.prtrst;
|
||||
}
|
||||
|
||||
static inline void usbh_ll_hprt_set_port_suspend(usbh_dev_t *hw)
|
||||
{
|
||||
usb_hprt_reg_t hprt;
|
||||
hprt.val = hw->hprt_reg.val;
|
||||
hprt.prtsusp = 1;
|
||||
hw->hprt_reg.val = hprt.val & (~USBH_LL_HPRT_W1C_MSK);
|
||||
}
|
||||
|
||||
static inline bool usbh_ll_hprt_get_port_suspend(usbh_dev_t *hw)
|
||||
{
|
||||
return hw->hprt_reg.prtsusp;
|
||||
}
|
||||
|
||||
static inline void usbh_ll_hprt_set_port_resume(usbh_dev_t *hw)
|
||||
{
|
||||
usb_hprt_reg_t hprt;
|
||||
hprt.val = hw->hprt_reg.val;
|
||||
hprt.prtres = 1;
|
||||
hw->hprt_reg.val = hprt.val & (~USBH_LL_HPRT_W1C_MSK);
|
||||
}
|
||||
|
||||
static inline void usbh_ll_hprt_clr_port_resume(usbh_dev_t *hw)
|
||||
{
|
||||
usb_hprt_reg_t hprt;
|
||||
hprt.val = hw->hprt_reg.val;
|
||||
hprt.prtres = 0;
|
||||
hw->hprt_reg.val = hprt.val & (~USBH_LL_HPRT_W1C_MSK);
|
||||
}
|
||||
|
||||
static inline bool usbh_ll_hprt_get_port_resume(usbh_dev_t *hw)
|
||||
{
|
||||
return hw->hprt_reg.prtres;
|
||||
}
|
||||
|
||||
static inline bool usbh_ll_hprt_get_port_overcur(usbh_dev_t *hw)
|
||||
{
|
||||
return hw->hprt_reg.prtovrcurract;
|
||||
}
|
||||
|
||||
static inline bool usbh_ll_hprt_get_port_en(usbh_dev_t *hw)
|
||||
{
|
||||
return hw->hprt_reg.prtena;
|
||||
}
|
||||
|
||||
static inline void usbh_ll_hprt_port_dis(usbh_dev_t *hw)
|
||||
{
|
||||
usb_hprt_reg_t hprt;
|
||||
hprt.val = hw->hprt_reg.val;
|
||||
hprt.prtena = 1; //W1C to disable
|
||||
//we want to W1C ENA but not W1C the interrupt bits
|
||||
hw->hprt_reg.val = hprt.val & ((~USBH_LL_HPRT_W1C_MSK) | USBH_LL_HPRT_ENA_MSK);
|
||||
}
|
||||
|
||||
static inline bool usbh_ll_hprt_get_conn_status(usbh_dev_t *hw)
|
||||
{
|
||||
return hw->hprt_reg.prtconnsts;
|
||||
}
|
||||
|
||||
static inline uint32_t usbh_ll_hprt_intr_read_and_clear(usbh_dev_t *hw)
|
||||
{
|
||||
usb_hprt_reg_t hprt;
|
||||
hprt.val = hw->hprt_reg.val;
|
||||
//We want to W1C the interrupt bits but not that ENA
|
||||
hw->hprt_reg.val = hprt.val & (~USBH_LL_HPRT_ENA_MSK);
|
||||
//Return only the interrupt bits
|
||||
return (hprt.val & (USBH_LL_HPRT_W1C_MSK & ~(USBH_LL_HPRT_ENA_MSK)));
|
||||
}
|
||||
|
||||
static inline void usbh_ll_hprt_intr_clear(usbh_dev_t *hw, uint32_t intr_mask)
|
||||
{
|
||||
usb_hprt_reg_t hprt;
|
||||
hprt.val = hw->hprt_reg.val;
|
||||
hw->hprt_reg.val = ((hprt.val & ~USBH_LL_HPRT_ENA_MSK) & ~USBH_LL_HPRT_W1C_MSK) | intr_mask;
|
||||
}
|
||||
|
||||
//Per Channel registers
|
||||
|
||||
// --------------------------- HCCHARi Register --------------------------------
|
||||
|
||||
static inline void usbh_ll_chan_start(volatile usb_host_chan_regs_t *chan)
|
||||
{
|
||||
chan->hcchar_reg.chena = 1;
|
||||
}
|
||||
|
||||
static inline bool usbh_ll_chan_is_active(volatile usb_host_chan_regs_t *chan)
|
||||
{
|
||||
return chan->hcchar_reg.chena;
|
||||
}
|
||||
|
||||
static inline void usbh_ll_chan_halt(volatile usb_host_chan_regs_t *chan)
|
||||
{
|
||||
chan->hcchar_reg.chdis = 1;
|
||||
}
|
||||
|
||||
static inline void usbh_ll_chan_xfer_odd_frame(volatile usb_host_chan_regs_t *chan)
|
||||
{
|
||||
chan->hcchar_reg.oddfrm = 1;
|
||||
}
|
||||
|
||||
static inline void usbh_ll_chan_xfer_even_frame(volatile usb_host_chan_regs_t *chan)
|
||||
{
|
||||
chan->hcchar_reg.oddfrm = 0;
|
||||
}
|
||||
|
||||
static inline void usbh_ll_chan_set_dev_addr(volatile usb_host_chan_regs_t *chan, uint32_t addr)
|
||||
{
|
||||
chan->hcchar_reg.devaddr = addr;
|
||||
}
|
||||
|
||||
static inline void usbh_ll_chan_set_ep_type(volatile usb_host_chan_regs_t *chan, usb_priv_xfer_type_t type)
|
||||
{
|
||||
uint32_t ep_type;
|
||||
switch (type) {
|
||||
case USB_PRIV_XFER_TYPE_CTRL:
|
||||
ep_type = 0;
|
||||
break;
|
||||
case USB_PRIV_XFER_TYPE_ISOCHRONOUS:
|
||||
ep_type = 1;
|
||||
break;
|
||||
case USB_PRIV_XFER_TYPE_BULK:
|
||||
ep_type = 2;
|
||||
break;
|
||||
default: //USB_PRIV_XFER_TYPE_INTR
|
||||
ep_type = 3;
|
||||
break;
|
||||
}
|
||||
chan->hcchar_reg.eptype = ep_type;
|
||||
}
|
||||
|
||||
//Indicates whether channel is commuunicating with a LS device connected via a FS hub. Setting this bit to 1 will cause
|
||||
//each packet to be preceded by a PREamble packet
|
||||
static inline void usbh_ll_chan_set_lspddev(volatile usb_host_chan_regs_t *chan, bool is_ls)
|
||||
{
|
||||
chan->hcchar_reg.lspddev = is_ls;
|
||||
}
|
||||
|
||||
static inline void usbh_ll_chan_set_dir(volatile usb_host_chan_regs_t *chan, bool is_in)
|
||||
{
|
||||
chan->hcchar_reg.epdir = is_in;
|
||||
}
|
||||
|
||||
static inline void usbh_ll_chan_set_ep_num(volatile usb_host_chan_regs_t *chan, uint32_t num)
|
||||
{
|
||||
chan->hcchar_reg.epnum = num;
|
||||
}
|
||||
|
||||
static inline void usbh_ll_chan_set_mps(volatile usb_host_chan_regs_t *chan, uint32_t mps)
|
||||
{
|
||||
chan->hcchar_reg.mps = mps;
|
||||
}
|
||||
|
||||
static inline void usbh_ll_chan_hcchar_init(volatile usb_host_chan_regs_t *chan, int dev_addr, int ep_num, int mps, usb_priv_xfer_type_t type, bool is_in, bool is_ls)
|
||||
{
|
||||
//Sets all persistent fields of the channel over its lifetimez
|
||||
usbh_ll_chan_set_dev_addr(chan, dev_addr);
|
||||
usbh_ll_chan_set_ep_type(chan, type);
|
||||
usbh_ll_chan_set_lspddev(chan, is_ls);
|
||||
usbh_ll_chan_set_dir(chan, is_in);
|
||||
usbh_ll_chan_set_ep_num(chan, ep_num);
|
||||
usbh_ll_chan_set_mps(chan, mps);
|
||||
}
|
||||
|
||||
// ---------------------------- HCINTi Register --------------------------------
|
||||
|
||||
static inline uint32_t usbh_ll_chan_intr_read_and_clear(volatile usb_host_chan_regs_t *chan)
|
||||
{
|
||||
usb_hcint_reg_t hcint;
|
||||
hcint.val = chan->hcint_reg.val;
|
||||
chan->hcint_reg.val = hcint.val;
|
||||
return hcint.val;
|
||||
}
|
||||
|
||||
// --------------------------- HCINTMSKi Register ------------------------------
|
||||
|
||||
static inline void usbh_ll_chan_set_intr_mask(volatile usb_host_chan_regs_t *chan, uint32_t mask)
|
||||
{
|
||||
chan->hcintmsk_reg.val = mask;
|
||||
}
|
||||
|
||||
// ---------------------- HCTSIZi and HCDMAi Registers -------------------------
|
||||
|
||||
static inline void usbh_ll_chan_set_pid(volatile usb_host_chan_regs_t *chan, uint32_t data_pid)
|
||||
{
|
||||
if (data_pid == 0) {
|
||||
chan->hctsiz_reg.pid = 0;
|
||||
} else {
|
||||
chan->hctsiz_reg.pid = 2;
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint32_t usbh_ll_chan_get_pid(volatile usb_host_chan_regs_t *chan) {
|
||||
if (chan->hctsiz_reg.pid == 0) {
|
||||
return 0; //DATA0
|
||||
} else {
|
||||
return 1; //DATA1
|
||||
}
|
||||
}
|
||||
|
||||
static inline void usbh_ll_chan_set_dma_addr_non_iso(volatile usb_host_chan_regs_t *chan,
|
||||
void *dmaaddr,
|
||||
uint32_t qtd_idx)
|
||||
{
|
||||
//Set HCDMAi
|
||||
chan->hcdma_reg.val = 0;
|
||||
chan->hcdma_reg.non_iso.dmaaddr = (((uint32_t)dmaaddr) >> 9) & 0x7FFFFF; //MSB of 512 byte aligned address
|
||||
chan->hcdma_reg.non_iso.ctd = qtd_idx;
|
||||
}
|
||||
|
||||
static inline void usbh_ll_chan_set_dma_addr_iso(volatile usb_host_chan_regs_t *chan,
|
||||
void *dmaaddr,
|
||||
uint32_t ntd)
|
||||
{
|
||||
int n;
|
||||
if (ntd == 2) {
|
||||
n = 4;
|
||||
} else if (ntd == 4) {
|
||||
n = 5;
|
||||
} else if (ntd == 8) {
|
||||
n = 6;
|
||||
} else if (ntd == 16) {
|
||||
n = 7;
|
||||
} else if (ntd == 32) {
|
||||
n = 8;
|
||||
} else { //ntd == 64
|
||||
n = 9;
|
||||
}
|
||||
//Set HCTSIZi
|
||||
chan->hctsiz_reg.ntd = ntd -1;
|
||||
chan->hctsiz_reg.sched_info = 0xFF; //Always set to 0xFF for FS
|
||||
//Set HCDMAi
|
||||
chan->hcdma_reg.iso.dmaaddr_ctd = (((uint32_t)dmaaddr) & 0x1FF) << (n-3); //ctd is set to 0
|
||||
}
|
||||
|
||||
static inline int usbh_ll_chan_get_ctd(usb_host_chan_regs_t *chan)
|
||||
{
|
||||
return chan->hcdma_reg.non_iso.ctd;
|
||||
}
|
||||
|
||||
static inline void usbh_ll_chan_hctsiz_init(volatile usb_host_chan_regs_t *chan)
|
||||
{
|
||||
chan->hctsiz_reg.dopng = 0; //Don't do ping
|
||||
chan->hctsiz_reg.sched_info = 0xFF; //Schedinfo is always 0xFF for fullspeed. Not used in Bulk/Ctrl channels
|
||||
}
|
||||
|
||||
static inline void usbh_ll_chan_set_qtd_list_len(volatile usb_host_chan_regs_t *chan, int qtd_list_len)
|
||||
{
|
||||
chan->hctsiz_reg.ntd = qtd_list_len - 1; //Set the length of the descriptor list
|
||||
}
|
||||
|
||||
// ---------------------------- HCDMABi Register -------------------------------
|
||||
|
||||
static inline void *usbh_ll_chan_get_cur_buff_addr(volatile usb_host_chan_regs_t *chan)
|
||||
{
|
||||
return (void *)chan->hcdmab_reg.hcdmab;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
---------------------------- Scatter/Gather DMA QTDs ---------------------------
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
// ---------------------------- Helper Functions -------------------------------
|
||||
|
||||
/**
|
||||
* @brief Get the base address of a channel's register based on the channel's index
|
||||
*
|
||||
* @param dev Start address of the DWC_OTG registers
|
||||
* @param chan_idx The channel's index
|
||||
* @return usb_host_chan_regs_t* Pointer to channel's registers
|
||||
*/
|
||||
static inline usb_host_chan_regs_t *usbh_ll_get_chan_regs(usbh_dev_t *dev, int chan_idx)
|
||||
{
|
||||
return &dev->host_chans[chan_idx];
|
||||
}
|
||||
|
||||
// ------------------------------ QTD related ----------------------------------
|
||||
|
||||
#define USBH_LL_QTD_STATUS_SUCCESS 0x0 //If QTD was processed, it indicates the data was transmitted/received successfully
|
||||
#define USBH_LL_QTD_STATUS_PKTERR 0x1 //Data trasnmitted/received with errors (CRC/Timeout/Stuff/False EOP/Excessive NAK).
|
||||
//Note: 0x2 is reserved
|
||||
#define USBH_LL_QTD_STATUS_BUFFER 0x3 //AHB error occurred.
|
||||
#define USBH_LL_QTD_STATUS_NOT_EXECUTED 0x4 //QTD as never processed
|
||||
|
||||
/**
|
||||
* @brief Set a QTD for a non isochronous IN transfer
|
||||
*
|
||||
* @param qtd Pointer to the QTD
|
||||
* @param data_buff Pointer to buffer containing the data to transfer
|
||||
* @param xfer_len Number of bytes in transfer. Setting 0 will do a zero length IN transfer.
|
||||
* Non zero length must be mulitple of the endpoint's MPS.
|
||||
* @param hoc Halt on complete (will generate an interrupt and halt the channel)
|
||||
*/
|
||||
static inline void usbh_ll_set_qtd_in(usbh_ll_dma_qtd_t *qtd, uint8_t *data_buff, int xfer_len, bool hoc)
|
||||
{
|
||||
qtd->buffer = data_buff; //Set pointer to data buffer
|
||||
qtd->buffer_status_val = 0; //Reset all flags to zero
|
||||
qtd->in_non_iso.xfer_size = xfer_len;
|
||||
if (hoc) {
|
||||
qtd->in_non_iso.intr_cplt = 1; //We need to set this to distinguish between a halt due to a QTD
|
||||
qtd->in_non_iso.eol = 1; //Used to halt the channel at this qtd
|
||||
}
|
||||
qtd->in_non_iso.active = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set a QTD for a non isochronous OUT transfer
|
||||
*
|
||||
* @param qtd Poitner to the QTD
|
||||
* @param data_buff Pointer to buffer containing the data to transfer
|
||||
* @param xfer_len Number of bytes to transfer. Setting 0 will do a zero length transfer.
|
||||
* For ctrl setup packets, this should be set to 8.
|
||||
* @param hoc Halt on complete (will generate an interrupt)
|
||||
* @param is_setup Indicates whether this is a control transfer setup packet or a normal OUT Data transfer.
|
||||
* (As per the USB protocol, setup packets cannot be STALLd or NAKd by the device)
|
||||
*/
|
||||
static inline void usbh_ll_set_qtd_out(usbh_ll_dma_qtd_t *qtd, uint8_t *data_buff, int xfer_len, bool hoc, bool is_setup)
|
||||
{
|
||||
qtd->buffer = data_buff; //Set pointer to data buffer
|
||||
qtd->buffer_status_val = 0; //Reset all flags to zero
|
||||
qtd->out_non_iso.xfer_size = xfer_len;
|
||||
if (is_setup) {
|
||||
qtd->out_non_iso.is_setup = 1;
|
||||
}
|
||||
if (hoc) {
|
||||
qtd->in_non_iso.intr_cplt = 1; //We need to set this to distinguish between a halt due to a QTD
|
||||
qtd->in_non_iso.eol = 1; //Used to halt the channel at this qtd
|
||||
}
|
||||
qtd->out_non_iso.active = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set a QTD as NULL
|
||||
*
|
||||
* This sets the QTD to a value of 0. This is only useful when you need to insert
|
||||
* blank QTDs into a list of QTDs
|
||||
*
|
||||
* @param qtd Pointer to the QTD
|
||||
*/
|
||||
static inline void usbh_ll_set_qtd_null(usbh_ll_dma_qtd_t *qtd)
|
||||
{
|
||||
qtd->buffer = NULL;
|
||||
qtd->buffer_status_val = 0; //Disable qtd by clearing it to zero. Used by interrupt/isoc as an unscheudled frame
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the status of a QTD
|
||||
*
|
||||
* When a channel get's halted, call this to check whether each QTD was executed successfully
|
||||
*
|
||||
* @param qtd Poitner to the QTD
|
||||
* @param[out] rem_len Number of bytes ramining in the QTD
|
||||
* @param[out] status Status of the QTD
|
||||
*/
|
||||
static inline void usbh_ll_get_qtd_status(usbh_ll_dma_qtd_t *qtd, int *rem_len, int *status)
|
||||
{
|
||||
//Status is the same regardless of IN or OUT
|
||||
if (qtd->in_non_iso.active) {
|
||||
//QTD was never processed
|
||||
*status = USBH_LL_QTD_STATUS_NOT_EXECUTED;
|
||||
} else {
|
||||
*status = qtd->in_non_iso.rx_status;
|
||||
}
|
||||
*rem_len = qtd->in_non_iso.xfer_size;
|
||||
//Clear the QTD just for safety
|
||||
qtd->buffer_status_val = 0;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
Reference in New Issue
Block a user