From a47c383233bb7cfcaa29db6e792e90ae8bdf13e2 Mon Sep 17 00:00:00 2001 From: Russ Butler Date: Wed, 28 Mar 2018 19:30:53 +0200 Subject: [PATCH] Update the STM32 USB driver to the new API Take the code from mbed-os\features\unsupported\USBDevice\targets\TARGET_STM as a starting point and use it to fill in the USBPhy template for STM32 devices. --- targets/targets.json | 3 +- .../targets/TARGET_STM/USBEndpoints_STM32.h | 65 +++ usb/device/targets/TARGET_STM/USBPhyHw.h | 102 ++++ .../targets/TARGET_STM/USBPhy_STM32.cpp | 522 ++++++++++++++++++ 4 files changed, 691 insertions(+), 1 deletion(-) create mode 100644 usb/device/targets/TARGET_STM/USBEndpoints_STM32.h create mode 100644 usb/device/targets/TARGET_STM/USBPhyHw.h create mode 100644 usb/device/targets/TARGET_STM/USBPhy_STM32.cpp diff --git a/targets/targets.json b/targets/targets.json index fd7f8f9fa8..a4f808a0c4 100644 --- a/targets/targets.json +++ b/targets/targets.json @@ -2222,7 +2222,8 @@ "SERIAL_ASYNCH", "FLASH", "TRNG", - "MPU" + "MPU", + "USBDEVICE" ], "device_has_remove": ["LPTICKER"], "release_versions": ["2", "5"], diff --git a/usb/device/targets/TARGET_STM/USBEndpoints_STM32.h b/usb/device/targets/TARGET_STM/USBEndpoints_STM32.h new file mode 100644 index 0000000000..a8723b2ae7 --- /dev/null +++ b/usb/device/targets/TARGET_STM/USBEndpoints_STM32.h @@ -0,0 +1,65 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018-2018 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define NUMBER_OF_LOGICAL_ENDPOINTS (4) +#define NUMBER_OF_PHYSICAL_ENDPOINTS (NUMBER_OF_LOGICAL_ENDPOINTS * 2) + +/* Define physical endpoint numbers */ + +/* Endpoint No. Type(s) MaxPacket DoubleBuffer */ +/* ---------------- ------------ ---------- --- */ +#define EP0OUT (0x00) /* Control 64 No */ +#define EP0IN (0x80) /* Control 64 No */ +#define EP1OUT (0x01) /* Int/Bulk/Iso 64/64/1023 Yes */ +#define EP1IN (0x81) /* Int/Bulk/Iso 64/64/1023 Yes */ +#define EP2OUT (0x02) /* Int/Bulk/Iso 64/64/1023 Yes */ +#define EP2IN (0x82) /* Int/Bulk/Iso 64/64/1023 Yes */ +#define EP3OUT (0x03) /* Int/Bulk/Iso 64/64/1023 Yes */ +#define EP3IN (0x83) /* Int/Bulk/Iso 64/64/1023 Yes */ + +/* Maximum Packet sizes */ +#define MAX_PACKET_SIZE_SETUP (48) +#define MAX_PACKET_SIZE_EP0 (64) +#define MAX_PACKET_SIZE_EP1 (64) /* Int/Bulk */ +#define MAX_PACKET_SIZE_EP2 (64) /* Int/Bulk */ +#define MAX_PACKET_SIZE_EP3 (200) /* Int/Bulk/iso (44100 stereo 16 bits) */ + +#define MAX_PACKET_SIZE_EP1_ISO (1023) /* Isochronous */ +#define MAX_PACKET_SIZE_EP2_ISO (1023) /* Isochronous */ +#define MAX_PACKET_SIZE_EP3_ISO (1023) /* Isochronous */ + +/* Generic endpoints - intended to be portable accross devices */ +/* and be suitable for simple USB devices. */ + +/* Bulk endpoint */ +#define EPBULK_OUT (EP2OUT) +#define EPBULK_IN (EP2IN) +#define EPBULK_OUT_callback EP2_OUT_callback +#define EPBULK_IN_callback EP2_IN_callback +/* Interrupt endpoint */ +#define EPINT_OUT (EP1OUT) +#define EPINT_IN (EP1IN) +#define EPINT_OUT_callback EP1_OUT_callback +#define EPINT_IN_callback EP1_IN_callback +/* Isochronous endpoint */ +#define EPISO_OUT (EP3OUT) +#define EPISO_IN (EP3IN) +#define EPISO_OUT_callback EP3_OUT_callback +#define EPISO_IN_callback EP3_IN_callback + +#define MAX_PACKET_SIZE_EPBULK (MAX_PACKET_SIZE_EP2) +#define MAX_PACKET_SIZE_EPINT (MAX_PACKET_SIZE_EP1) +#define MAX_PACKET_SIZE_EPISO (MAX_PACKET_SIZE_EP3_ISO) diff --git a/usb/device/targets/TARGET_STM/USBPhyHw.h b/usb/device/targets/TARGET_STM/USBPhyHw.h new file mode 100644 index 0000000000..b117339c84 --- /dev/null +++ b/usb/device/targets/TARGET_STM/USBPhyHw.h @@ -0,0 +1,102 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018-2018 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef USBPHYHW_H +#define USBPHYHW_H + +#include "mbed.h" +#include "USBPhy.h" + +#if defined(TARGET_DISCO_F746NG) +#if (MBED_CONF_TARGET_USB_SPEED == 1) // Defined in json configuration file +#define TARGET_DISCO_F746NG_OTG_HS +#else +#define TARGET_DISCO_F746NG_OTG_FS +#endif +#endif + +#if defined(TARGET_DISCO_F429ZI) || \ + defined(TARGET_DISCO_F769NI) || \ + defined(TARGET_DISCO_F746NG_OTG_HS) +#define USBHAL_IRQn OTG_HS_IRQn +#else +#define USBHAL_IRQn OTG_FS_IRQn +#endif + +#include "USBEndpoints_STM32.h" + +#define NB_ENDPOINT 4 // Must be a multiple of 4 bytes + +#define MAXTRANSFER_SIZE 0x200 + +#define FIFO_USB_RAM_SIZE (MAXTRANSFER_SIZE + MAX_PACKET_SIZE_EP0 + MAX_PACKET_SIZE_EP1 + MAX_PACKET_SIZE_EP2 + MAX_PACKET_SIZE_EP3) + +#if (FIFO_USB_RAM_SIZE > 0x500) +#error "FIFO dimensioning incorrect" +#endif + +class USBPhyHw : public USBPhy { +public: + USBPhyHw(); + virtual ~USBPhyHw(); + virtual void init(USBPhyEvents *events); + virtual void deinit(); + virtual bool powered(); + virtual void connect(); + virtual void disconnect(); + virtual void configure(); + virtual void unconfigure(); + virtual void sof_enable(); + virtual void sof_disable(); + virtual void set_address(uint8_t address); + virtual void remote_wakeup(); + virtual const usb_ep_table_t* endpoint_table(); + + virtual uint32_t ep0_set_max_packet(uint32_t max_packet); + virtual void ep0_setup_read_result(uint8_t *buffer, uint32_t size); + virtual void ep0_read(uint8_t *data, uint32_t size); + virtual uint32_t ep0_read_result(); + virtual void ep0_write(uint8_t *buffer, uint32_t size); + virtual void ep0_stall(); + + virtual bool endpoint_add(usb_ep_t endpoint, uint32_t max_packet, usb_ep_type_t type); + virtual void endpoint_remove(usb_ep_t endpoint); + virtual void endpoint_stall(usb_ep_t endpoint); + virtual void endpoint_unstall(usb_ep_t endpoint); + + virtual bool endpoint_read(usb_ep_t endpoint, uint8_t *data, uint32_t size); + virtual uint32_t endpoint_read_result(usb_ep_t endpoint); + virtual bool endpoint_write(usb_ep_t endpoint, uint8_t *data, uint32_t size); + virtual void endpoint_abort(usb_ep_t endpoint); + + virtual void process(); + + USBPhyEvents *events; + bool sof_enabled; + + uint8_t epComplete[2 * NB_ENDPOINT]; + uint32_t pBufRx[MAXTRANSFER_SIZE >> 2]; + uint32_t pBufRx0[MAX_PACKET_SIZE_EP0 >> 2]; + PCD_HandleTypeDef hpcd; + +private: + uint32_t _read_size[16]; + uint8_t *_read_buf[16]; + + static void _usbisr(void); +}; + +#endif diff --git a/usb/device/targets/TARGET_STM/USBPhy_STM32.cpp b/usb/device/targets/TARGET_STM/USBPhy_STM32.cpp new file mode 100644 index 0000000000..09c9804726 --- /dev/null +++ b/usb/device/targets/TARGET_STM/USBPhy_STM32.cpp @@ -0,0 +1,522 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018-2018 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* TARGET NOT STM does not support this HAL */ +#ifndef TARGET_STM +#define USBSTM_HAL_UNSUPPORTED +#endif + +/* STM32F4 family without USB_STM_HAL use another HAL */ +#if defined(TARGET_STM) && defined(TARGET_STM32F4) && !defined(USB_STM_HAL) +#define USBSTM_HAL_UNSUPPORTED +#endif + +#ifndef USBSTM_HAL_UNSUPPORTED +#include "USBPhyHw.h" +#include "pinmap.h" + + +/* endpoint conversion macros */ +#define EP_TO_LOG(ep) ((ep) & 0x7F) +#define EP_TO_IDX(ep) (((ep) << 1) | ((ep) & 0x80 ? 1 : 0)) +#define LOG_IN_TO_EP(ep) ((ep) | 0x80) +#define LOG_OUT_TO_EP(ep) ((ep) | 0x00) +#define IDX_TO_EP(ep) (((ep) >> 1)|((ep) & 1) << 7) + +uint32_t HAL_PCDEx_GetTxFiFo(PCD_HandleTypeDef *hpcd, uint8_t fifo) +{ + uint32_t len; + if (fifo == 0) { + len = hpcd->Instance->DIEPTXF0_HNPTXFSIZ >> 16; + } + else { + len = hpcd->Instance->DIEPTXF[fifo - 1] >> 16; + } + return len * 4; +} + +void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) +{ + USBPhyHw *priv=((USBPhyHw *)(hpcd->pData)); + USB_OTG_GlobalTypeDef *USBx = hpcd->Instance; + if (priv->sof_enabled) { + priv->events->sof((USBx_DEVICE->DSTS & USB_OTG_DSTS_FNSOF) >> 8); + } +} + +/* this call at device reception completion on a Out Enpoint */ +void HAL_PCD_DataOutStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) +{ + USBPhyHw *priv=((USBPhyHw *)(hpcd->pData)); + uint8_t endpoint = LOG_OUT_TO_EP(epnum); + priv->epComplete[EP_TO_IDX(endpoint)] = 1; + /* -2 endpoint 0 In out are not in call back list */ + if (epnum) { + priv->events->out(endpoint); + } else { + priv->events->ep0_out(); + } +} + +/* this is call at device transmission completion on In endpoint */ +void HAL_PCD_DataInStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) +{ + USBPhyHw *priv=((USBPhyHw *)(hpcd->pData)); + uint8_t endpoint = LOG_IN_TO_EP(epnum); + priv->epComplete[EP_TO_IDX(endpoint)] = 1; + /* -2 endpoint 0 In out are not in call back list */ + if (epnum) { + priv->events->in(endpoint); + } else { + priv->events->ep0_in(); + } +} +/* This is call at device set up reception */ +void HAL_PCD_SetupStageCallback(PCD_HandleTypeDef *hpcd) +{ + USBPhyHw *priv=((USBPhyHw *)(hpcd->pData)); + priv->events->ep0_setup(); +} + +void HAL_PCD_SuspendCallback(PCD_HandleTypeDef *hpcd) +{ + USBPhyHw *priv=((USBPhyHw *)(hpcd->pData)); + priv->events->suspend(1); +} + +void HAL_PCD_ResumeCallback(PCD_HandleTypeDef *hpcd) +{ + USBPhyHw *priv=((USBPhyHw *)(hpcd->pData)); + priv->events->suspend(0); +} + +void HAL_PCD_ConnectCallback(PCD_HandleTypeDef *hpcd) +{ + // Nothing to do +} + +void HAL_PCD_DisconnectCallback(PCD_HandleTypeDef *hpcd) +{ + // Nothing to do +} + +void HAL_PCD_ResetCallback(PCD_HandleTypeDef *hpcd) +{ + USBPhyHw *obj=((USBPhyHw *)(hpcd->pData)); + unsigned int i; + for(i=0;iInit.dev_endpoints;i++) { + obj->epComplete[2*i]=0; + HAL_PCD_EP_Close(hpcd,IDX_TO_EP(2*i)); + HAL_PCD_EP_Flush(hpcd,IDX_TO_EP(2*i)); + obj->epComplete[2*i+1]=0; + HAL_PCD_EP_Close(hpcd,IDX_TO_EP(2*i+1)); + HAL_PCD_EP_Flush(hpcd,IDX_TO_EP(2*i+1)); + + } + obj->endpoint_add(EP0IN, MAX_PACKET_SIZE_EP0, USB_EP_TYPE_CTRL); + obj->endpoint_add(EP0OUT, MAX_PACKET_SIZE_EP0, USB_EP_TYPE_CTRL); + obj->events->reset(); +} + + +/* hal pcd handler , used for STM32 HAL PCD Layer */ + +static USBPhyHw *instance; + +USBPhy *get_usb_phy() +{ + static USBPhyHw usbphy; + return &usbphy; +} + +USBPhyHw::USBPhyHw(): events(NULL), sof_enabled(false) +{ + +} + +USBPhyHw::~USBPhyHw() +{ + +} + +void USBPhyHw::init(USBPhyEvents *events) +{ + NVIC_DisableIRQ(USBHAL_IRQn); + + this->events = events; + sof_enabled = false; + memset(epComplete, 0, sizeof(epComplete)); + memset(pBufRx, 0, sizeof(pBufRx)); + memset(pBufRx0, 0, sizeof(pBufRx0)); + memset(&hpcd.Init, 0, sizeof(hpcd.Init)); + memset(_read_size, 0, sizeof(_read_size)); + memset(_read_buf, 0, sizeof(_read_buf)); + +#if defined(TARGET_DISCO_F769NI) || \ + defined(TARGET_DISCO_F746NG_OTG_HS) + hpcd.Instance = USB_OTG_HS; + hpcd.Init.phy_itface = PCD_PHY_ULPI; + hpcd.Init.Sof_enable = 1; + hpcd.Init.speed = PCD_SPEED_HIGH; +#elif defined(TARGET_DISCO_F429ZI) + hpcd.Instance = USB_OTG_HS; + hpcd.Init.phy_itface = PCD_PHY_EMBEDDED; + hpcd.Init.Sof_enable = 1; + hpcd.Init.speed = PCD_SPEED_HIGH; +#else + hpcd.Instance = USB_OTG_FS; + hpcd.Init.phy_itface = PCD_PHY_EMBEDDED; + hpcd.Init.Sof_enable = 1; + hpcd.Init.speed = PCD_SPEED_FULL; +#endif + hpcd.Init.dev_endpoints = NB_ENDPOINT; + hpcd.Init.ep0_mps = MAX_PACKET_SIZE_EP0; + + // Pass instance for usage inside call back + instance = this; + + // Configure USB pins and other clocks + +#if defined(TARGET_NUCLEO_F207ZG) || \ + defined(TARGET_NUCLEO_F401RE) || \ + defined(TARGET_NUCLEO_F411RE) || \ + defined(TARGET_NUCLEO_F412ZG) || \ + defined(TARGET_NUCLEO_F413ZH) || \ + defined(TARGET_NUCLEO_F429ZI) || \ + defined(TARGET_NUCLEO_F446RE) || \ + defined(TARGET_NUCLEO_F446ZE) || \ + defined(TARGET_NUCLEO_F767ZI) || \ + defined(TARGET_NUCLEO_F746ZG) || \ + defined(TARGET_DISCO_F407VG) || \ + defined(TARGET_DISCO_F413ZH) || \ + defined(TARGET_DISCO_F469NI) || \ + defined(TARGET_DISCO_F746NG_OTG_FS) + __HAL_RCC_GPIOA_CLK_ENABLE(); + pin_function(PA_11, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF10_OTG_FS)); // DM + pin_function(PA_12, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF10_OTG_FS)); // DP + pin_function(PA_9, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, GPIO_AF10_OTG_FS)); // VBUS + pin_function(PA_10, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_PULLUP, GPIO_AF10_OTG_FS)); // ID + pin_function(PA_8, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF10_OTG_FS)); // SOF + __HAL_RCC_USB_OTG_FS_CLK_ENABLE(); + +#elif defined(TARGET_DISCO_F429ZI) + __HAL_RCC_GPIOB_CLK_ENABLE(); + pin_function(PB_14, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF12_OTG_HS_FS)); // DM + pin_function(PB_15, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF12_OTG_HS_FS)); // DP + pin_function(PB_13, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, 0)); // VBUS + __HAL_RCC_USB_OTG_HS_CLK_ENABLE(); + +#elif defined(TARGET_DISCO_L475VG_IOT01A) || \ + defined(TARGET_DISCO_L476VG) + __HAL_RCC_GPIOA_CLK_ENABLE(); + pin_function(PA_11, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF10_OTG_FS)); // DM + pin_function(PA_12, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF10_OTG_FS)); // DP + __HAL_RCC_GPIOC_CLK_ENABLE(); + pin_function(PC_11, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF10_OTG_FS)); // VBUS + __HAL_RCC_PWR_CLK_ENABLE(); + HAL_PWREx_EnableVddUSB(); + __HAL_RCC_USB_OTG_FS_CLK_ENABLE(); + +#elif defined(TARGET_DISCO_F769NI) || \ + defined(TARGET_DISCO_F746NG_OTG_HS) + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOH_CLK_ENABLE(); + __HAL_RCC_GPIOI_CLK_ENABLE(); + pin_function(PA_5, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF10_OTG_HS)); // CLK + pin_function(PA_3, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF10_OTG_HS)); // D0 + pin_function(PB_0, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF10_OTG_HS)); // D1 + pin_function(PB_1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF10_OTG_HS)); // D2 + pin_function(PB_5, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF10_OTG_HS)); // D3 + pin_function(PB_10, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF10_OTG_HS)); // D4 + pin_function(PB_11, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF10_OTG_HS)); // D5 + pin_function(PB_12, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF10_OTG_HS)); // D6 + pin_function(PB_13, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF10_OTG_HS)); // D7 + pin_function(PC_0, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF10_OTG_HS)); // STP + pin_function(PH_4, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF10_OTG_HS)); // NXT +#if defined(TARGET_DISCO_F769NI) + pin_function(PI_11, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF10_OTG_HS)); // DIR +#else // TARGET_DISCO_F746NG + pin_function(PC_2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF10_OTG_HS)); // DIR +#endif + __HAL_RCC_USB_OTG_HS_ULPI_CLK_ENABLE(); + __HAL_RCC_USB_OTG_HS_CLK_ENABLE(); + +#elif defined(TARGET_STEVAL_3DP001V1) + __HAL_RCC_GPIOB_CLK_ENABLE(); + pin_function(PA_11, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF10_OTG_FS)); // DM + pin_function(PA_12, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_NOPULL, GPIO_AF10_OTG_FS)); // DP + __HAL_RCC_USB_OTG_FS_CLK_ENABLE(); + +#else +#error "USB pins are not configured !" +#endif + + __HAL_RCC_SYSCFG_CLK_ENABLE(); + + // Configure PCD and FIFOs + hpcd.pData = (void*)this; + hpcd.State = HAL_PCD_STATE_RESET; + HAL_PCD_Init(&hpcd); + + /* 1.25 kbytes */ + /* min value 16 (= 16 x 4 bytes) */ + /* max value 256 (= 1K bytes ) */ + /* maximum sum is 0x140 */ + HAL_PCDEx_SetRxFiFo(&hpcd, (MAXTRANSFER_SIZE / 4)); + + // Configure interrupt vector + NVIC_SetVector(USBHAL_IRQn, (uint32_t)&_usbisr); + NVIC_SetPriority(USBHAL_IRQn, 1); + NVIC_EnableIRQ(USBHAL_IRQn); +} + +void USBPhyHw::deinit() +{ + HAL_PCD_DeInit(&hpcd); + NVIC_DisableIRQ(USBHAL_IRQn); +} + +bool USBPhyHw::powered() +{ + return true; +} + +void USBPhyHw::connect() +{ + HAL_PCD_Start(&hpcd); +} + +void USBPhyHw::disconnect() +{ + HAL_PCD_Stop(&hpcd); +} + +void USBPhyHw::configure() +{ + // Not needed +} + +void USBPhyHw::unconfigure() +{ + // Not needed +} + +void USBPhyHw::sof_enable() +{ + sof_enabled = true; +} + +void USBPhyHw::sof_disable() +{ + sof_enabled = false; +} + +void USBPhyHw::set_address(uint8_t address) +{ + HAL_PCD_SetAddress(&hpcd, address); + ep0_write(NULL, 0); +} + +void USBPhyHw::remote_wakeup() +{ + +} + +const usb_ep_table_t *USBPhyHw::endpoint_table() +{ + static const usb_ep_table_t table = { + 1280, // 1.25K for endpoint buffers + { + {USB_EP_ATTR_ALLOW_CTRL | USB_EP_ATTR_DIR_IN_AND_OUT, 1, 80}, + {USB_EP_ATTR_ALLOW_ALL | USB_EP_ATTR_DIR_IN_AND_OUT, 1, 4}, + {USB_EP_ATTR_ALLOW_ALL | USB_EP_ATTR_DIR_IN_AND_OUT, 1, 4}, + {USB_EP_ATTR_ALLOW_ALL | USB_EP_ATTR_DIR_IN_AND_OUT, 1, 4}, + {USB_EP_ATTR_ALLOW_ALL | USB_EP_ATTR_DIR_IN_AND_OUT, 1, 4}, + {0 | USB_EP_ATTR_DIR_IN_AND_OUT, 1, 4}, + {0 | USB_EP_ATTR_DIR_IN_AND_OUT, 1, 4}, + {0 | USB_EP_ATTR_DIR_IN_AND_OUT, 1, 4}, + {0 | USB_EP_ATTR_DIR_IN_AND_OUT, 1, 4}, + {0 | USB_EP_ATTR_DIR_IN_AND_OUT, 1, 4}, + {0 | USB_EP_ATTR_DIR_IN_AND_OUT, 1, 4}, + {0 | USB_EP_ATTR_DIR_IN_AND_OUT, 1, 4}, + {0 | USB_EP_ATTR_DIR_IN_AND_OUT, 1, 4}, + {0 | USB_EP_ATTR_DIR_IN_AND_OUT, 1, 4}, + {0 | USB_EP_ATTR_DIR_IN_AND_OUT, 1, 4}, + {0 | USB_EP_ATTR_DIR_IN_AND_OUT, 1, 4} + } + }; + return &table; +} + +uint32_t USBPhyHw::ep0_set_max_packet(uint32_t max_packet) +{ + // FUTURE - set endpoint 0 size and return this size + return MAX_PACKET_SIZE_EP0; +} + +// read setup packet +void USBPhyHw::ep0_setup_read_result(uint8_t *buffer, uint32_t size) +{ + if (size > MAX_PACKET_SIZE_SETUP) { + size = MAX_PACKET_SIZE_SETUP; + } + memcpy(buffer, hpcd.Setup, size); + memset(hpcd.Setup,0,MAX_PACKET_SIZE_SETUP); +} + +void USBPhyHw::ep0_read(uint8_t *data, uint32_t size) +{ + _read_buf[0] = data; + _read_size[0] = size; + + uint8_t *pBuf = (uint8_t *)pBufRx0; + HAL_StatusTypeDef ret; + epComplete[EP_TO_IDX(EP0OUT)] = 2; + ret = HAL_PCD_EP_Receive(&hpcd, EP0OUT, pBuf, MAX_PACKET_SIZE_EP0 ); + MBED_ASSERT(ret!=HAL_BUSY); +} + +uint32_t USBPhyHw::ep0_read_result() +{ + uint32_t length = (uint32_t) HAL_PCD_EP_GetRxCount(&hpcd, 0); + epComplete[EP_TO_IDX(EP0OUT)] = 0; + if (length) { + uint8_t *buff = (uint8_t *)pBufRx0; + memcpy(_read_buf[0], buff, _read_size[0] > length ? length : _read_size[0]); + } + _read_buf[0] = 0; + _read_size[0] = 0; + return length; +} + +void USBPhyHw::ep0_write(uint8_t *buffer, uint32_t size) +{ + /* check that endpoint maximum size is not exceeding TX fifo */ + MBED_ASSERT(hpcd.IN_ep[0].maxpacket >= size); + endpoint_write(EP0IN, buffer, size); +} + +void USBPhyHw::ep0_stall() +{ + endpoint_stall(EP0IN); + endpoint_stall(EP0OUT); +} + +bool USBPhyHw::endpoint_add(usb_ep_t endpoint, uint32_t max_packet, usb_ep_type_t type) +{ + uint32_t len; + if (max_packet > MAXTRANSFER_SIZE) return false; + if (endpoint & 0x80) { + HAL_PCDEx_SetTxFiFo(&hpcd, endpoint & 0x7f, (max_packet / 4) + 1); + len = HAL_PCDEx_GetTxFiFo(&hpcd,endpoint & 0x7f); + MBED_ASSERT(len >= max_packet); + } + HAL_StatusTypeDef ret = HAL_PCD_EP_Open(&hpcd, endpoint, max_packet, type); + MBED_ASSERT(ret!=HAL_BUSY); + return (ret == HAL_OK) ? true:false; +} + +void USBPhyHw::endpoint_remove(usb_ep_t endpoint) +{ + HAL_StatusTypeDef ret = HAL_PCD_EP_Close(&hpcd, endpoint); + MBED_ASSERT(ret == HAL_OK); +} + +void USBPhyHw::endpoint_stall(usb_ep_t endpoint) +{ + HAL_StatusTypeDef ret; + ret = HAL_PCD_EP_SetStall(&hpcd, endpoint); + MBED_ASSERT(ret!=HAL_BUSY); +} + +void USBPhyHw::endpoint_unstall(usb_ep_t endpoint) +{ + HAL_StatusTypeDef ret; + ret = HAL_PCD_EP_ClrStall(&hpcd, endpoint); + MBED_ASSERT(ret!=HAL_BUSY); +} + +bool USBPhyHw::endpoint_read(usb_ep_t endpoint, uint8_t *data, uint32_t size) +{ + _read_buf[EP_TO_LOG(endpoint)] = data; + _read_size[EP_TO_LOG(endpoint)] = size; + + uint8_t* pBuf = (uint8_t *)pBufRx; //TODO - this buffer shouldn't be shared for multiple endpoints + HAL_StatusTypeDef ret; + // clean reception end flag before requesting reception + ret = HAL_PCD_EP_Receive(&hpcd, endpoint, pBuf, size); + MBED_ASSERT(ret!=HAL_BUSY); + return true; +} + +uint32_t USBPhyHw::endpoint_read_result(usb_ep_t endpoint) +{ + uint8_t *buffer =_read_buf[EP_TO_LOG(endpoint)]; + uint8_t max_size = _read_size[EP_TO_LOG(endpoint)]; + + if (epComplete[EP_TO_IDX(endpoint)]==0) { + /* no reception possible !!! */ + return 0; + } else if ((epComplete[EP_TO_IDX(endpoint)]!=1)) { + return 0; + } + uint8_t *buff = (uint8_t *)pBufRx; + uint32_t length = (uint32_t) HAL_PCD_EP_GetRxCount(&hpcd, endpoint); + memcpy(buffer, buff, length > max_size ? max_size : length); + epComplete[EP_TO_IDX(endpoint)]= 0; + return length; +} + +bool USBPhyHw::endpoint_write(usb_ep_t endpoint, uint8_t *data, uint32_t size) +{ + HAL_StatusTypeDef ret; + // clean transmission end flag before requesting transmission + epComplete[EP_TO_IDX(endpoint)] = 2; + ret = HAL_PCD_EP_Transmit(&hpcd, endpoint, data, size); + MBED_ASSERT(ret!=HAL_BUSY); + // update the status + if (ret != HAL_OK) return false; + // fix me return is too simple + return true; +} + +void USBPhyHw::endpoint_abort(usb_ep_t endpoint) +{ + // TODO - stop the current transfer on this endpoint and don't call the IN or OUT callback +} + +void USBPhyHw::process() +{ + HAL_PCD_IRQHandler(&instance->hpcd); + // Re-enable interrupt + NVIC_ClearPendingIRQ(USBHAL_IRQn); + NVIC_EnableIRQ(USBHAL_IRQn); +} + +void USBPhyHw::_usbisr(void) { + NVIC_DisableIRQ(USBHAL_IRQn); + instance->events->start_process(); +} + +//TODO - remove this hack which allows HAL_Delay to work when interrupts are disabled +extern "C" uint32_t HAL_GetTick() +{ + return ticker_read_us(get_us_ticker_data()) / 1000; +} + +#endif