ROM Comm / USBDevice_STM32F103

Fork of USBDevice_STM32F103 by Devan Lai

Files at this revision

API Documentation at this revision

Comitter:
va009039
Date:
Fri Jun 12 09:17:50 2015 +0000
Parent:
56:151ba33713ff
Child:
58:68fad4f36f1c
Commit message:
for NUCLEO-L152RE

Changed in this revision

USBDevice/USBEndpoints.h Show annotated file Show diff for this revision Revisions of this file
USBDevice/USBEndpoints_STM32L1.h Show annotated file Show diff for this revision Revisions of this file
USBDevice/USBHAL.h Show annotated file Show diff for this revision Revisions of this file
USBDevice/USBHAL_STM32L1.cpp Show annotated file Show diff for this revision Revisions of this file
--- a/USBDevice/USBEndpoints.h	Mon Jun 08 08:15:25 2015 +0100
+++ b/USBDevice/USBEndpoints.h	Fri Jun 12 09:17:50 2015 +0000
@@ -45,6 +45,8 @@
 #include "USBEndpoints_KL25Z.h"
 #elif defined (TARGET_STM32F4)
 #include "USBEndpoints_STM32F4.h"
+#elif defined(TARGET_STM32L1)
+#include "USBEndpoints_STM32L1.h"
 #elif defined (TARGET_RZ_A1H)
 #include "USBEndpoints_RZ_A1H.h"
 #elif defined(TARGET_Maxim)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBDevice/USBEndpoints_STM32L1.h	Fri Jun 12 09:17:50 2015 +0000
@@ -0,0 +1,67 @@
+/* Copyright (c) 2010-2015 mbed.org, MIT License
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+* and associated documentation files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use, copy, modify, merge, publish,
+* distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or
+* substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#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      (0)  /* Control       64          No            */
+#define EP0IN       (1)  /* Control       64          No            */
+#define EP1OUT      (2)  /* Int/Bulk/Iso  64/64/1023  Yes           */
+#define EP1IN       (3)  /* Int/Bulk/Iso  64/64/1023  Yes           */
+#define EP2OUT      (4)  /* Int/Bulk/Iso  64/64/1023  Yes           */
+#define EP2IN       (5)  /* Int/Bulk/Iso  64/64/1023  Yes           */
+#define EP3OUT      (6)  /* Int/Bulk/Iso  64/64/1023  Yes           */
+#define EP3IN       (7)  /* Int/Bulk/Iso  64/64/1023  Yes           */
+
+/* Maximum Packet sizes */
+
+#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 (64) /* Int/Bulk */
+
+#define MAX_PACKET_SIZE_EP1_ISO (192) /* Isochronous */
+#define MAX_PACKET_SIZE_EP2_ISO (192) /* Isochronous */
+#define MAX_PACKET_SIZE_EP3_ISO (192) /* 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)
--- a/USBDevice/USBHAL.h	Mon Jun 08 08:15:25 2015 +0100
+++ b/USBDevice/USBHAL.h	Fri Jun 12 09:17:50 2015 +0000
@@ -74,7 +74,7 @@
     virtual bool EP2_IN_callback(){return false;};
     virtual bool EP3_OUT_callback(){return false;};
     virtual bool EP3_IN_callback(){return false;};
-#if !defined(TARGET_STM32F4)
+#if !defined(TARGET_STM32F4) || defined(TARGET_STM32L1)
     virtual bool EP4_OUT_callback(){return false;};
     virtual bool EP4_IN_callback(){return false;};
 #if !(defined(TARGET_LPC11UXX) || defined(TARGET_LPC11U6X) || defined(TARGET_LPC1347) || defined(TARGET_LPC1549))
@@ -117,5 +117,13 @@
 #endif
 
 
+#if defined(TARGET_STM32L1)
+public: // HAL_PCD
+    void SetupStageCallback();
+    void DataInStageCallback(uint8_t epnum);
+    void DataOutStageCallback(uint8_t epnum);
+    void ResetCallback();
+    void SOFCallback();
+#endif // TARGET_STM32L1
 };
 #endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBDevice/USBHAL_STM32L1.cpp	Fri Jun 12 09:17:50 2015 +0000
@@ -0,0 +1,414 @@
+/* Copyright (c) 2010-2015 mbed.org, MIT License
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+* and associated documentation files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use, copy, modify, merge, publish,
+* distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or
+* substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#if defined(TARGET_STM32L1)
+#include "USBDevice.h"
+
+static PCD_HandleTypeDef hpcd_USB_FS;
+static volatile int epComplete = 0;
+
+USBHAL * USBHAL::instance;
+uint32_t USBHAL::endpointReadcore(uint8_t endpoint, uint8_t *buffer) {return 0;}
+
+extern "C" void USB_LP_IRQHandler(void) {
+    HAL_PCD_IRQHandler(&hpcd_USB_FS);
+}
+
+USBHAL::USBHAL(void) {
+    hpcd_USB_FS.pData = this;
+    hpcd_USB_FS.Instance = USB;
+    hpcd_USB_FS.Init.dev_endpoints = 8;
+    hpcd_USB_FS.Init.speed = PCD_SPEED_FULL;
+    hpcd_USB_FS.Init.ep0_mps = DEP0CTL_MPS_8;
+    hpcd_USB_FS.Init.phy_itface = PCD_PHY_EMBEDDED;
+    hpcd_USB_FS.Init.Sof_enable = DISABLE;
+    hpcd_USB_FS.Init.low_power_enable = DISABLE;
+    hpcd_USB_FS.Init.battery_charging_enable = DISABLE;
+    HAL_PCD_Init(&hpcd_USB_FS);
+    HAL_PCD_Start(&hpcd_USB_FS);
+}
+
+void HAL_PCD_MspInit(PCD_HandleTypeDef* hpcd) {
+    __USB_CLK_ENABLE();
+    HAL_NVIC_SetPriority(USB_LP_IRQn, 0, 0);
+    HAL_NVIC_EnableIRQ(USB_LP_IRQn);
+}
+
+USBHAL::~USBHAL(void) {}
+
+void USBHAL::connect(void) {
+    MBED_ASSERT(hpcd_USB_FS.Instance == USB);
+}
+
+void USBHAL::disconnect(void) {
+}
+
+void USBHAL::configureDevice(void) {
+    // Not needed
+}
+void USBHAL::unconfigureDevice(void) {
+    // Not needed
+}
+
+void USBHAL::setAddress(uint8_t address) {
+    HAL_PCD_SetAddress(&hpcd_USB_FS, address);
+}
+
+class PacketBufferAreaManager {
+public:
+    PacketBufferAreaManager() {
+        reset();
+    }
+    void reset() { 
+        head = 0; 
+        tail = 512; 
+    }
+    int allocBuf(int maxPacketSize) {
+        head += 4;
+        tail -= maxPacketSize;
+        if (tail < head) {
+            return 0;
+        }
+        return tail;
+    }
+private:
+    int head,tail;
+} PktBufArea;
+
+bool USBHAL::realiseEndpoint(uint8_t endpoint, uint32_t maxPacket, uint32_t flags) {
+    int pmaadress = PktBufArea.allocBuf(maxPacket);
+    MBED_ASSERT(pmaadress != 0);
+    if (pmaadress == 0) {
+        return false;
+    }
+    PCD_HandleTypeDef *hpcd = &hpcd_USB_FS;
+    switch(endpoint) {
+        case EP0IN:
+            HAL_PCDEx_PMAConfig(hpcd, 0x80, PCD_SNG_BUF, pmaadress);
+            HAL_PCD_EP_Open(hpcd, 0x80, maxPacket, PCD_EP_TYPE_CTRL);
+            break;
+        case EP0OUT:
+            HAL_PCDEx_PMAConfig(hpcd, 0x00, PCD_SNG_BUF, pmaadress);
+            HAL_PCD_EP_Open(hpcd, 0x00, maxPacket, PCD_EP_TYPE_CTRL);
+            break;
+        case EPINT_IN:
+            HAL_PCDEx_PMAConfig(hpcd, 0x81, PCD_SNG_BUF, pmaadress);
+            HAL_PCD_EP_Open(hpcd, 0x81, maxPacket, PCD_EP_TYPE_INTR);
+            break;
+        case EPINT_OUT:
+            HAL_PCDEx_PMAConfig(hpcd, 0x01, PCD_SNG_BUF, pmaadress);
+            HAL_PCD_EP_Open(hpcd, 0x01, maxPacket, PCD_EP_TYPE_INTR);
+            break;
+        case EPBULK_IN:
+            HAL_PCDEx_PMAConfig(hpcd, 0x82, PCD_SNG_BUF, pmaadress);
+            HAL_PCD_EP_Open(hpcd, 0x82, maxPacket, PCD_EP_TYPE_BULK);
+            break;
+        case EPBULK_OUT:
+            HAL_PCDEx_PMAConfig(hpcd, 0x02, PCD_SNG_BUF, pmaadress);
+            HAL_PCD_EP_Open(hpcd, 0x02, maxPacket, PCD_EP_TYPE_BULK);
+            break;
+        case EPISO_IN:
+            MBED_ASSERT(flags == ISOCHRONOUS);
+            HAL_PCDEx_PMAConfig(hpcd, 0x83, PCD_SNG_BUF, pmaadress);
+            HAL_PCD_EP_Open(hpcd, 0x83, maxPacket, PCD_EP_TYPE_ISOC);
+            break;
+        case EPISO_OUT:
+            MBED_ASSERT(flags == ISOCHRONOUS);
+            HAL_PCDEx_PMAConfig(hpcd, 0x03, PCD_SNG_BUF, pmaadress);
+            HAL_PCD_EP_Open(hpcd, 0x03, maxPacket, PCD_EP_TYPE_ISOC);
+            break;
+        default:
+            MBED_ASSERT(0);
+            return false;
+    }
+    return true;
+}
+
+// read setup packet
+void USBHAL::EP0setup(uint8_t *buffer) {
+    memcpy(buffer, hpcd_USB_FS.Setup, 8);
+}
+
+void USBHAL::EP0readStage(void) {
+}
+
+void USBHAL::EP0read(void) {
+    endpointRead(EP0OUT, MAX_PACKET_SIZE_EP0);
+}
+
+static uint8_t* rxTempBuffer(uint8_t endpoint) {
+    switch(endpoint) {
+        case EP0OUT:
+            static uint8_t buf0[MAX_PACKET_SIZE_EP0];
+            return buf0;
+        case EP1OUT:
+            static uint8_t buf1[MAX_PACKET_SIZE_EP1];
+            return buf1;
+        case EP2OUT:
+            static uint8_t buf2[MAX_PACKET_SIZE_EP2];
+            return buf2;
+        case EP3OUT:
+            static uint8_t buf3[MAX_PACKET_SIZE_EP3_ISO];
+            return buf3;
+    }
+    MBED_ASSERT(0);
+    return NULL;
+}
+
+uint32_t USBHAL::EP0getReadResult(uint8_t *buffer) {
+    const uint8_t endpoint = EP0OUT;
+    uint32_t length = HAL_PCD_EP_GetRxCount(&hpcd_USB_FS, endpoint>>1);
+    memcpy(buffer, rxTempBuffer(endpoint), length);
+    return length;
+}
+
+void USBHAL::EP0write(uint8_t *buffer, uint32_t size) {
+    endpointWrite(EP0IN, buffer, size);
+}
+
+void USBHAL::EP0getWriteResult(void) {
+}
+
+void USBHAL::EP0stall(void) {
+    // If we stall the out endpoint here then we have problems transferring
+    // and setup requests after the (stalled) get device qualifier requests.
+    // TODO: Find out if this is correct behavior, or whether we are doing
+    // something else wrong
+    stallEndpoint(EP0IN);
+//    stallEndpoint(EP0OUT);
+}
+
+EP_STATUS USBHAL::endpointRead(uint8_t endpoint, uint32_t maximumSize) {
+    HAL_PCD_EP_Receive(&hpcd_USB_FS, endpoint>>1, rxTempBuffer(endpoint), maximumSize);
+    epComplete &= ~(1 << endpoint);
+    return EP_PENDING;
+}
+
+EP_STATUS USBHAL::endpointReadResult(uint8_t endpoint, uint8_t * buffer, uint32_t *bytesRead) {
+    if (!(epComplete & (1 << endpoint))) {
+        return EP_PENDING;
+    }
+    int len = HAL_PCD_EP_GetRxCount(&hpcd_USB_FS, endpoint>>1);
+    MBED_ASSERT(len <= 64);
+    memcpy(buffer, rxTempBuffer(endpoint), len);
+    *bytesRead = len;
+    return EP_COMPLETED;
+}
+
+EP_STATUS USBHAL::endpointWrite(uint8_t endpoint, uint8_t *data, uint32_t size) {
+    HAL_PCD_EP_Transmit(&hpcd_USB_FS, endpoint>>1, data, size);
+    epComplete &= ~(1 << endpoint);
+    return EP_PENDING;
+}
+
+EP_STATUS USBHAL::endpointWriteResult(uint8_t endpoint) {
+    if (epComplete & (1 << endpoint)) {
+        epComplete &= ~(1 << endpoint);
+        return EP_COMPLETED;
+    }
+    return EP_PENDING;
+}
+
+void USBHAL::stallEndpoint(uint8_t endpoint) {
+    PCD_HandleTypeDef *hpcd = &hpcd_USB_FS;
+    switch(endpoint) {
+        case EP0IN:
+            HAL_PCD_EP_SetStall(hpcd, 0x80);
+            break;
+        case EP0OUT:
+            HAL_PCD_EP_SetStall(hpcd, 0x00);
+            break;
+        default:
+            break;
+    }
+}
+
+void USBHAL::unstallEndpoint(uint8_t endpoint) {
+}
+
+bool USBHAL::getEndpointStallState(uint8_t endpoint) {
+    return false;
+}
+
+void USBHAL::remoteWakeup(void) {}
+void USBHAL::_usbisr(void) {}
+void USBHAL::usbisr(void) {}
+
+void USBHAL::SetupStageCallback() {
+    EP0setupCallback();
+}
+
+void USBHAL::DataInStageCallback(uint8_t epnum) {
+    switch(epnum) {
+        case 0: // EP0IN
+            EP0in();
+            break;
+        case 1: 
+            epComplete |= (1<<EP1IN);
+            if (EP1_IN_callback()) {
+                epComplete &= ~(1<<EP1IN);
+            }
+            break;
+        case 2:
+            epComplete |= (1<<EP2IN);
+            if (EP2_IN_callback()) {
+                epComplete &= ~(1<<EP2IN);
+            }
+            break;
+        case 3: 
+            epComplete |= (1<<EP3IN);
+            if (EP3_IN_callback()) {
+                epComplete &= ~(1<<EP3IN);
+            }
+            break;
+        default:
+            MBED_ASSERT(0);
+            break;
+    }
+}
+
+void USBHAL::DataOutStageCallback(uint8_t epnum) {
+    switch(epnum) {
+        case 0: // EP0OUT
+            EP0out();
+            break;
+        case 1:
+            epComplete |= (1<<EP1OUT);
+            if (EP1_OUT_callback()) {
+                epComplete &= ~(1<<EP1OUT);
+            }
+            break;
+        case 2:
+            epComplete |= (1<<EP2OUT);
+            if (EP2_OUT_callback()) {
+                epComplete &= ~(1<<EP2OUT);
+            }
+            break;
+        case 3:
+            epComplete |= (1<<EP3OUT);
+            if (EP3_OUT_callback()) {
+                epComplete &= ~(1<<EP3OUT);
+            }
+            break;
+        default:
+            MBED_ASSERT(0);
+            break;
+    }
+}
+
+void USBHAL::ResetCallback() {
+    PktBufArea.reset();
+    realiseEndpoint(EP0IN, MAX_PACKET_SIZE_EP0, 0);
+    realiseEndpoint(EP0OUT, MAX_PACKET_SIZE_EP0, 0);
+}
+
+void USBHAL::SOFCallback() {
+    SOF(hpcd_USB_FS.Instance->FNR & 0x7fff);
+}
+
+void HAL_PCD_SetupStageCallback(PCD_HandleTypeDef *hpcd) {
+    reinterpret_cast<USBHAL*>(hpcd->pData)->SetupStageCallback();
+}
+
+void HAL_PCD_DataInStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) {
+    reinterpret_cast<USBHAL*>(hpcd->pData)->DataInStageCallback(epnum);
+}
+
+void HAL_PCD_DataOutStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) {
+    reinterpret_cast<USBHAL*>(hpcd->pData)->DataOutStageCallback(epnum);
+}
+
+void HAL_PCD_ResetCallback(PCD_HandleTypeDef *hpcd) {
+    reinterpret_cast<USBHAL*>(hpcd->pData)->ResetCallback();
+}
+
+void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) {
+    reinterpret_cast<USBHAL*>(hpcd->pData)->SOFCallback();
+}
+
+void HAL_PCD_SuspendCallback(PCD_HandleTypeDef *hpcd) {
+    if (hpcd->Init.low_power_enable) {
+        SCB->SCR |= (uint32_t)((uint32_t)(SCB_SCR_SLEEPDEEP_Msk | SCB_SCR_SLEEPONEXIT_Msk));
+    }
+}
+
+void HAL_PCDEx_SetConnectionState(PCD_HandleTypeDef *hpcd, uint8_t state) {
+    if (state == 1) {
+        __HAL_SYSCFG_USBPULLUP_ENABLE();
+    } else {
+        __HAL_SYSCFG_USBPULLUP_DISABLE();
+    } 
+}
+
+
+void L152RE_SystemClock_Config(void) {
+    RCC_OscInitTypeDef RCC_OscInitStruct;
+    RCC_ClkInitTypeDef RCC_ClkInitStruct;
+
+    __PWR_CLK_ENABLE();
+
+    __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
+
+    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
+    RCC_OscInitStruct.HSIState = RCC_HSI_ON;
+    RCC_OscInitStruct.HSICalibrationValue = 16;
+    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
+    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
+    RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL6;
+    RCC_OscInitStruct.PLL.PLLDIV = RCC_PLL_DIV3;
+    HAL_RCC_OscConfig(&RCC_OscInitStruct);
+
+    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK;
+    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
+    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
+    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
+    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
+    HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1);
+
+    __SYSCFG_CLK_ENABLE();
+}
+
+uint32_t L152RE_getUSBclock() {
+    RCC_OscInitTypeDef cfg;
+    HAL_RCC_GetOscConfig(&cfg);
+    MBED_ASSERT(cfg.PLL.PLLState == RCC_PLL_ON);
+    uint32_t src = (cfg.PLL.PLLSource == RCC_PLLSOURCE_HSI) ? HSI_VALUE : HSE_VALUE;
+    MBED_ASSERT(src == 16000000 || src == 8000000);
+    switch(cfg.PLL.PLLMUL) {
+        case RCC_PLL_MUL3: src *= 3; break;
+        case RCC_PLL_MUL4: src *= 4; break;
+        case RCC_PLL_MUL6: src *= 6; break;
+        case RCC_PLL_MUL8: src *= 8; break;
+        case RCC_PLL_MUL12: src *= 12; break;
+        case RCC_PLL_MUL16: src *= 16; break;
+        case RCC_PLL_MUL24: src *= 24; break;
+        case RCC_PLL_MUL32: src *= 32; break;
+        case RCC_PLL_MUL48: src *= 48; break;
+    }
+    return src / 2;
+}
+
+void L152RE_USBclock_setup() {
+    if (L152RE_getUSBclock() != 48000000) {
+        HAL_RCC_DeInit();
+        L152RE_SystemClock_Config();
+    }
+}
+
+#endif
+