Przeglądaj źródła

Added batterry charging detection support

Dmitry 9 lat temu
rodzic
commit
5558726719
8 zmienionych plików z 128 dodań i 20 usunięć
  1. 2 2
      demo/cdc_loop.c
  2. 32 4
      inc/usbd_core.h
  3. 6 6
      readme.md
  4. 22 2
      src/usb_32v0.c
  5. 34 1
      src/usb_32v0A.S
  6. 2 1
      src/usb_32v1.c
  7. 1 0
      src/usb_32v1A.S
  8. 29 4
      src/usb_32v2.c

+ 2 - 2
demo/cdc_loop.c

@@ -283,8 +283,8 @@ static void cdc_init_usbd(void) {
 
 void main(void) {
     cdc_init_usbd();
-    usbd_control(&udev, usbd_cmd_enable);
-    usbd_control(&udev, usbd_cmd_connect);
+    usbd_enable(&udev, true);
+    usbd_connect(&udev, true);
     while(1) {
     usbd_poll(&udev);
     }

+ 32 - 4
inc/usbd_core.h

@@ -48,7 +48,6 @@
 #define USB_REQ_OTHER           (3 << 0)
 /** @} */
 
-
 /** \name USB device events
  * @{ */
 #define usbd_evt_reset      0   /**< Reset */
@@ -63,10 +62,21 @@
 #define usbd_evt_count      9
 /** @} */
 
+/**\anchor USB_LANE_STATUS
+ * \name USB lanes connection states
+ * @{ */
+#define usbd_lane_unk       0   /**< Unknown or proprietary charger */
+#define usbd_lane_dsc       1   /**< Lanes disconnected */
+#define usbd_lane_sdp       2   /**< Connected to standard downstream port */
+#define usbd_lane_cdp       3   /**< Connected to charging downstream port */
+#define usbd_lane_dcp       4   /**< Connected to dedicated charging port */
+/** @} */
+
+
 /** \name USB HW capabilities
  * @{ */
 #define USBD_HW_ADDRFST     (1 << 0)    /**< Set address before STATUS_OUT */
-
+#define USBD_HW_BC          (1 << 1)    /**< Battery charging detection supported */
 /** @} */
 
 #if !defined(__ASSEMBLER__)
@@ -177,8 +187,9 @@ typedef void (*usbd_hw_reset)(void);
 
 /** Connects or disconnects USB hardware to/from usb host
  * \param connect Connects USB to host if TRUE, disconnects otherwise
+ * \return lanes connection status. \ref USB_LANES_STATUS
  */
-typedef void (*usbd_hw_connect)(bool connect);
+typedef uint8_t (*usbd_hw_connect)(bool connect);
 
 /** Sets USB hardware address
  * \param address USB address
@@ -328,7 +339,7 @@ void usbd_poll(usbd_device *dev);
  * \param dev USB device
  * \param cmd control command
  */
-void usbd_control(usbd_device *dev, enum usbd_commands cmd);
+void usbd_control(usbd_device *dev, enum usbd_commands cmd) __attribute__((deprecated));
 
 /** Register callback for all control requests
  * \param dev pointer to \ref usbd_device structure
@@ -420,6 +431,23 @@ inline static void usbd_ep_unstall(usbd_device *dev, uint8_t ep) {
     dev->driver->ep_setstall(ep, 0);
 }
 
+/** Enables or disables USB hardware
+ * \param dev pointer to \ref usbd_device structure
+ * \param enable Enables USB when TRUE disables otherwise
+ */
+inline static void usbd_enable(usbd_device *dev, bool enable) {
+    dev->driver->enable(enable);
+}
+
+/** Connects or disconnects USB hardware to/from usb host
+ * \param dev pointer to \ref usbd_device structure
+ * \param connect Connects USB to host if TRUE, disconnects otherwise
+ * \return lanes connection status. \ref USB_LANES_STATUS
+ */
+inline static uint8_t usbd_connect(usbd_device *dev, bool connect) {
+    return dev->driver->connect(connect);
+}
+
 #endif //(__ASSEMBLER__)
 /** @} */
 /** @} */

+ 6 - 6
readme.md

@@ -9,11 +9,11 @@
 
 | HW driver  | Written on | Endpoints |                     Features | MCU series |
 |------------|------------|-----------|------------------------------|------------|
-| usb_stmv0  | GCC C      | 8         | Internal S/N, Doublebuffered | STM32L0x2 STM32L0x3 STM32L4x2 STM32L4x3 STM32F0x2 STM32F0x8 |
-| usb_stmv0a | GCC ASM    | 8         | Internal S/N, Doublebuffered | STM32L0x2 STM32L0x3 STM32L4x2 STM32L4x3 STM32F0x2 STM32F0x8 |
+| usb_stmv0  | GCC C      | 8         | Internal S/N, Doublebuffered, BC1.2 | STM32L0x2 STM32L0x3 STM32L4x2 STM32L4x3 STM32F0x2 STM32F0x8 |
+| usb_stmv0a | GCC ASM    | 8         | Internal S/N, Doublebuffered, BC1.2 | STM32L0x2 STM32L0x3 STM32L4x2 STM32L4x3 STM32F0x2 STM32F0x8 |
 | usb_stmv1  | GCC C      | 8         | Internal S/N, Doublebuffered | STM32L1xx  |
 | usb_stmv1a | GCC ASM    | 8         | Internal S/N, Doublebuffered | STM32L1xx  |
-| usb_stmv2  | GCC C      | 6         | Internal S/N, Doublebuffered | STM32L4x5 STM32L4x6 (OTG FS (Device mode)) |
+| usb_stmv2  | GCC C      | 6         | Internal S/N, Doublebuffered, BC1.2 | STM32L4x5 STM32L4x6 (OTG FS (Device mode)) |
 
 1. Single physical endpoint can be used to implement
   + one bi-directional/single-buffer logical endpoint (CONTROL)
@@ -22,14 +22,14 @@
 
 2. At this moment BULK IN endpoint can use both buffers, but it is not **real** doublebuffered.
 
-3. Tested with STM32L052, STM31L100
+3. Tested with STM32L052, STM31L100, STM32L476RG
 
 ### Implemented definitions for classes ###
 1. USB HID based on [Device Class Definition for Human Interface Devices (HID) Version 1.11](http://www.usb.org/developers/hidpage/HID1_11.pdf)
 2. USB DFU based on [USB Device Firmware Upgrade Specification, Revision 1.1](http://www.usb.org/developers/docs/devclass_docs/DFU_1.1.pdf)
 3. USB CDC based on [Class definitions for Communication Devices 1.2](http://www.usb.org/developers/docs/devclass_docs/CDC1.2_WMC1.1_012011.zip)
 
-###Using make###
+### Using makefile ###
 + to build library module
 ```
 make module MODULE=path/module.a DEFINES="mcu spcified defines" CFLAGS="cpu cpecified compiler flags"
@@ -44,8 +44,8 @@ make demo MCU=stm32l476rg
 ```
 make program
 ```
-#Default values:#
 
+### Default values: ###
 | Variable | Default Value                       | Means                         |
 |----------|-------------------------------------|-------------------------------|
 | CMSIS    | ../../cmsis                         | path to CMSIS root folder     |

+ 22 - 2
src/usb_32v0.c

@@ -158,8 +158,28 @@ void reset (void) {
     USB->CNTR &= ~USB_CNTR_FRES;
 }
 
-void connect(bool connect) {
+uint8_t connect(bool connect) {
+    uint8_t res;
+    USB->BCDR = USB_BCDR_BCDEN | USB_BCDR_DCDEN;
+    if (USB->BCDR & USB_BCDR_DCDET) {
+        USB->BCDR = USB_BCDR_BCDEN | USB_BCDR_PDEN;
+        if (USB->BCDR & USB_BCDR_PS2DET) {
+            res = usbd_lane_unk;
+        } else if (USB->BCDR & USB_BCDR_PDET) {
+            USB->BCDR = USB_BCDR_BCDEN | USB_BCDR_SDEN;
+            if (USB->BCDR & USB_BCDR_SDET) {
+                res = usbd_lane_dcp;
+            } else {
+                res = usbd_lane_cdp;
+            }
+        } else {
+            res = usbd_lane_sdp;
+        }
+    } else {
+        res = usbd_lane_dsc;
+    }
     USB->BCDR = (connect) ? USB_BCDR_DPPU : 0;
+    return res;
 }
 
 void setaddr (uint8_t addr) {
@@ -432,7 +452,7 @@ uint16_t get_serialno_desc(void *buffer) {
 }
 
 const struct usbd_driver usb_stmv0 = {
-    0,
+    USBD_HW_BC,
     enable,
     reset,
     connect,

+ 34 - 1
src/usb_32v0A.S

@@ -83,7 +83,7 @@
     .globl  usb_stmv0a
     .align  2
 usb_stmv0a:
-    .long   0
+    .long   USBD_HW_BC
     .long   _enable
     .long   _reset
     .long   _connect
@@ -163,12 +163,45 @@ _get_serial_desc:
     .thumb_func
     .type   _connect, %function
 _connect:
+#if 1
+    ldr     r3, =#USB_REGBASE
+    movs    r1, #0x03               //BCDEN + DCDEN
+    movs    r2, #usbd_lane_dsc
+    strh    r1, [r3, #USB_BCDR]
+    ldrh    r1, [r3, #USB_BCDR]
+    lsrs    r1, #0x05               //DCDET->CF
+    bcc     .L_connect
+    movs    r1, #0x05               //BCDEN + PDEN
+    movs    r2, #usbd_lane_unk
+    strh    r1, [r3, #USB_BCDR]
+    ldrh    r1, [r3, #USB_BCDR]
+    lsls    r1, #25                 //PS2DET->CF
+    bcs     .L_connect
+    movs    r2, #usbd_lane_sdp
+    lsls    r1, #2                  //PDET->CF
+    bcc     .L_connect
+    movs    r1, #0x09               //BCDEN + SDET
+    movs    r2, #usbd_lane_cdp
+    strh    r1, [r3, #USB_BCDR]
+    ldrh    r1, [r3, #USB_BCDR]
+    lsrs    r1, #7                  //SDET->CF
+    bcc     .L_connect
+    movs    r2, #usbd_lane_dcp
+.L_connect:
+    subs    r1, r0, #1
+    sbcs    r0, r1
+    lsls    r0, #15
+    strh    r1, [r3, #USB_BCDR]
+    mov     r0, r2
+    bx      lr
+#else
     subs    r1, r0, #1
     sbcs    r0, r1
     lsls    r0, #15
     ldr     r1, =#USB_REGBASE
     strh    r0, [r1, #USB_BCDR]      //USB->BCDR
     bx      lr
+#endif
     .size   _connect, . - _connect
 
 

+ 2 - 1
src/usb_32v1.c

@@ -161,12 +161,13 @@ void reset (void) {
     USB->CNTR &= ~USB_CNTR_FRES;
 }
 
-void connect(bool connect) {
+uint8_t connect(bool connect) {
     if (connect) {
         SYSCFG->PMC |= SYSCFG_PMC_USB_PU;
     } else {
         SYSCFG->PMC &= ~SYSCFG_PMC_USB_PU;
     }
+    return usbd_lane_unk;
 }
 
 void setaddr (uint8_t addr) {

+ 1 - 0
src/usb_32v1A.S

@@ -170,6 +170,7 @@ _connect:
     orrs    r2, r3
 .L_conn_store:
     str     r2, [r1, #SYSCFG_PMC]
+    movs    r0, #usbd_lane_unk
     bx      lr
     .size   _connect, . - _connect
 

+ 29 - 4
src/usb_32v2.c

@@ -21,7 +21,6 @@
 #if defined(USE_STMV2_DRIVER)
 
 #define VBUS_DETECTION  0
-
 #define MAX_EP          6
 #define MAX_RX_PACKET   128
 #define MAX_CONTROL_EP  1
@@ -153,12 +152,38 @@ void reset (void) {
 }
 
 
-void connect(bool connect) {
+uint8_t connect(bool connect) {
+    uint8_t res;
+#if (VBUS_DETECTION)
+    #define SET_GCCFG(x) OTG->GCCFG = USB_OTG_GCCFG_VBDEN | (x)
+#else
+    #define SET_GCCFG(x) OTG->GCCFG = (x)
+#endif
+    SET_GCCFG(USB_OTG_GCCFG_BCDEN | USB_OTG_GCCFG_DCDEN);
+    if (OTG->GCCFG & USB_OTG_GCCFG_DCDET) {
+        SET_GCCFG(USB_OTG_GCCFG_BCDEN | USB_OTG_GCCFG_PDEN);
+        if (OTG->GCCFG & USB_OTG_GCCFG_PS2DET) {
+            res = usbd_lane_unk;
+        } else if (OTG->GCCFG & USB_OTG_GCCFG_PDET) {
+            SET_GCCFG(USB_OTG_GCCFG_BCDEN | USB_OTG_GCCFG_SDEN);
+            if (OTG->GCCFG & USB_OTG_GCCFG_SDET) {
+                res = usbd_lane_dcp;
+            } else {
+                res = usbd_lane_cdp;
+            }
+        } else {
+            res = usbd_lane_sdp;
+        }
+    } else {
+        res = usbd_lane_dsc;
+    }
+    SET_GCCFG(USB_OTG_GCCFG_PWRDWN);
     if (connect) {
         _BCL(OTGD->DCTL, USB_OTG_DCTL_SDIS);
     } else {
         _BST(OTGD->DCTL, USB_OTG_DCTL_SDIS);
     }
+    return res;
 }
 
 void setaddr (uint8_t addr) {
@@ -325,7 +350,7 @@ int32_t ep_read(uint8_t ep, void* buf, uint16_t blen) {
     if ((OTG->GRXSTSR & USB_OTG_GRXSTSP_EPNUM) != ep) return -1;
     /* pop data from fifo */
     len = _FLD2VAL(USB_OTG_GRXSTSP_BCNT, OTG->GRXSTSP);
-    for (int i = 0; i < len; i +=4) {
+    for (unsigned i = 0; i < len; i +=4) {
         uint32_t _t = *fifo;
         if (blen >= 4) {
             *(__attribute__((packed))uint32_t*)buf = _t;
@@ -453,7 +478,7 @@ uint16_t get_serialno_desc(void *buffer) {
 }
 
 const struct usbd_driver usb_stmv2 = {
-    USBD_HW_ADDRFST,
+    USBD_HW_ADDRFST | USBD_HW_BC,
     enable,
     reset,
     connect,