2 ******************************************************************************
3 * @addtogroup PIOS PIOS Core hardware abstraction layer
5 * @addtogroup PIOS_USB USB Setup Functions
6 * @brief PIOS USB device implementation
10 * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
11 * @brief USB device functions (STM32 dependent code)
12 * @see The GNU Public License (GPL) Version 3
14 *****************************************************************************/
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 3 of the License, or
19 * (at your option) any later version.
21 * This program is distributed in the hope that it will be useful, but
22 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
23 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
26 * You should have received a copy of the GNU General Public License along
27 * with this program; if not, write to the Free Software Foundation, Inc.,
28 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
33 #ifdef PIOS_INCLUDE_USB
36 #include "pios_usb_board_data.h"
37 #include <pios_usb_priv.h>
38 #include <pios_helpers.h>
41 static uint8_t transfer_possible
= 0;
43 static void(*disconnection_cb_list
[3]) (void);
45 enum pios_usb_dev_magic
{
46 PIOS_USB_DEV_MAGIC
= 0x17365904,
50 enum pios_usb_dev_magic magic
;
51 const struct pios_usb_cfg
*cfg
;
52 #ifdef PIOS_INCLUDE_FREERTOS
53 xSemaphoreHandle statusCheckSemaphore
;
56 #ifdef PIOS_INCLUDE_FREERTOS
57 static void raiseDisconnectionCallbacks(void);
60 * @brief Validate the usb device structure
61 * @returns true if valid device or false otherwise
63 static bool PIOS_USB_validate(struct pios_usb_dev
*usb_dev
)
65 return usb_dev
&& (usb_dev
->magic
== PIOS_USB_DEV_MAGIC
);
68 #if defined(PIOS_INCLUDE_FREERTOS)
69 static struct pios_usb_dev
*PIOS_USB_alloc(void)
71 struct pios_usb_dev
*usb_dev
;
73 usb_dev
= (struct pios_usb_dev
*)pios_malloc(sizeof(*usb_dev
));
77 vSemaphoreCreateBinary(usb_dev
->statusCheckSemaphore
);
78 xSemaphoreGive(usb_dev
->statusCheckSemaphore
);
79 usb_dev
->magic
= PIOS_USB_DEV_MAGIC
;
83 static struct pios_usb_dev pios_usb_devs
[PIOS_USB_MAX_DEVS
];
84 static uint8_t pios_usb_num_devs
;
85 static struct pios_usb_dev
*PIOS_USB_alloc(void)
87 struct pios_usb_dev
*usb_dev
;
89 if (pios_usb_num_devs
>= PIOS_USB_MAX_DEVS
) {
93 usb_dev
= &pios_usb_devs
[pios_usb_num_devs
++];
94 usb_dev
->magic
= PIOS_USB_DEV_MAGIC
;
98 #endif /* if defined(PIOS_INCLUDE_FREERTOS) */
102 * Bind configuration to USB BSP layer
103 * \return < 0 if initialisation failed
105 static uint32_t pios_usb_id
;
106 int32_t PIOS_USB_Init(uint32_t *usb_id
, const struct pios_usb_cfg
*cfg
)
111 struct pios_usb_dev
*usb_dev
;
113 usb_dev
= (struct pios_usb_dev
*)PIOS_USB_alloc();
118 /* Bind the configuration to the device instance */
122 * This is a horrible hack to make this available to
123 * the interrupt callbacks. This should go away ASAP.
125 pios_usb_id
= (uint32_t)usb_dev
;
127 *usb_id
= (uint32_t)usb_dev
;
129 return 0; /* No error */
136 * This function is called by the USB driver on cable connection/disconnection
137 * \param[in] connected connection status (1 if connected)
138 * \return < 0 on errors
139 * \note Applications shouldn't call this function directly, instead please use \ref PIOS_COM layer functions
141 int32_t PIOS_USB_ChangeConnectionState(bool connected
)
143 // In all cases: re-initialise USB HID driver
145 transfer_possible
= 1;
147 // TODO: Check SetEPRxValid(ENDP1);
149 #if defined(USB_LED_ON)
150 USB_LED_ON
; // turn the USB led on
153 // Cable disconnected: disable transfers
154 transfer_possible
= 0;
156 #if defined(USB_LED_OFF)
157 USB_LED_OFF
; // turn the USB led off
165 * This function returns the connection status of the USB interface
166 * \return 1: interface available
167 * \return 0: interface not available
170 bool PIOS_USB_CheckAvailable(__attribute__((unused
)) uint32_t id
)
172 struct pios_usb_dev
*usb_dev
= (struct pios_usb_dev
*)pios_usb_id
;
174 if (!PIOS_USB_validate(usb_dev
)) {
178 usb_found
= ((usb_dev
->cfg
->vsense
.gpio
->IDR
& usb_dev
->cfg
->vsense
.init
.GPIO_Pin
) != 0) ^ usb_dev
->cfg
->vsense_active_low
;
179 // Please note that checks of transfer_possible and the reconnection handling is
180 // suppressed for non freertos mode (aka bootloader) as this is causing problems detecting connection and
181 // broken communications.
182 #ifdef PIOS_INCLUDE_FREERTOS
183 static bool lastStatus
= false;
184 bool status
= usb_found
!= 0 && transfer_possible
? 1 : 0;
185 bool reconnect
= false;
186 if (xSemaphoreTakeFromISR(usb_dev
->statusCheckSemaphore
, NULL
) == pdTRUE
) {
187 reconnect
= (lastStatus
&& !status
);
189 xSemaphoreGiveFromISR(usb_dev
->statusCheckSemaphore
, NULL
);
192 raiseDisconnectionCallbacks();
204 * Register a physical disconnection callback
207 void PIOS_USB_RegisterDisconnectionCallback(void (*disconnectionCB
)(void))
209 PIOS_Assert(disconnectionCB
);
210 for (uint32_t i
= 0; i
< NELEMENTS(disconnection_cb_list
); i
++) {
211 if (disconnection_cb_list
[i
] == NULL
) {
212 disconnection_cb_list
[i
] = disconnectionCB
;
218 #ifdef PIOS_INCLUDE_FREERTOS
219 static void raiseDisconnectionCallbacks(void)
223 while (i
< NELEMENTS(disconnection_cb_list
) && disconnection_cb_list
[i
] != NULL
) {
224 (disconnection_cb_list
[i
++])();
230 * Provide STM32 USB OTG BSP layer API
236 void USB_OTG_BSP_Init(__attribute__((unused
)) USB_OTG_CORE_HANDLE
*pdev
)
238 struct pios_usb_dev
*usb_dev
= (struct pios_usb_dev
*)pios_usb_id
;
240 bool valid
= PIOS_USB_validate(usb_dev
);
244 #define FORCE_DISABLE_USB_IRQ 1
245 #if FORCE_DISABLE_USB_IRQ
246 /* Make sure we disable the USB interrupt since it may be left on by bootloader */
247 NVIC_InitTypeDef NVIC_InitStructure
;
248 NVIC_InitStructure
= usb_dev
->cfg
->irq
.init
;
249 NVIC_InitStructure
.NVIC_IRQChannelCmd
= DISABLE
;
250 NVIC_Init(&NVIC_InitStructure
);
253 /* Configure USB D-/D+ (DM/DP) pins */
254 GPIO_InitTypeDef GPIO_InitStructure
;
255 GPIO_InitStructure
.GPIO_Pin
= GPIO_Pin_11
| GPIO_Pin_12
;
256 GPIO_InitStructure
.GPIO_Speed
= GPIO_Speed_100MHz
;
257 GPIO_InitStructure
.GPIO_Mode
= GPIO_Mode_AF
;
258 GPIO_InitStructure
.GPIO_OType
= GPIO_OType_PP
;
259 GPIO_InitStructure
.GPIO_PuPd
= GPIO_PuPd_NOPULL
;
260 GPIO_Init(GPIOA
, &GPIO_InitStructure
);
262 GPIO_PinAFConfig(GPIOA
, GPIO_PinSource11
, GPIO_AF_OTG_FS
);
263 GPIO_PinAFConfig(GPIOA
, GPIO_PinSource12
, GPIO_AF_OTG_FS
);
265 /* Configure VBUS sense pin */
266 GPIO_Init(usb_dev
->cfg
->vsense
.gpio
, &usb_dev
->cfg
->vsense
.init
);
268 /* Enable USB OTG Clock */
269 RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_OTG_FS
, ENABLE
);
272 void USB_OTG_BSP_EnableInterrupt(__attribute__((unused
)) USB_OTG_CORE_HANDLE
*pdev
)
274 struct pios_usb_dev
*usb_dev
= (struct pios_usb_dev
*)pios_usb_id
;
276 bool valid
= PIOS_USB_validate(usb_dev
);
280 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4
);
282 NVIC_Init(&usb_dev
->cfg
->irq
.init
);
286 void USB_OTG_BSP_DriveVBUS(USB_OTG_CORE_HANDLE
*pdev
, uint8_t state
)
289 void USB_OTG_BSP_ConfigVBUS(USB_OTG_CORE_HANDLE
*pdev
)
291 #endif /* USE_HOST_MODE */
293 void USB_OTG_BSP_TimeInit(void)
296 void USB_OTG_BSP_uDelay(const uint32_t usec
)
299 const uint32_t utime
= (120 * usec
/ 7);
302 if (++count
> utime
) {
308 void USB_OTG_BSP_mDelay(const uint32_t msec
)
310 USB_OTG_BSP_uDelay(msec
* 1000);
313 void USB_OTG_BSP_TimerIRQ(void)
316 #endif /* PIOS_INCLUDE_USB */