2 * This file is part of Cleanflight and Betaflight.
4 * Cleanflight and Betaflight are free software. You can redistribute
5 * this software and/or modify this software under the terms of the
6 * GNU General Public License as published by the Free Software
7 * Foundation, either version 3 of the License, or (at your option)
10 * Cleanflight and Betaflight are distributed in the hope that they
11 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
12 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this software.
18 * If not, see <http://www.gnu.org/licenses/>.
28 #include "build/build_config.h"
29 #include "build/atomic.h"
31 #include "common/utils.h"
33 #include "drivers/io.h"
34 #include "drivers/usb_io.h"
38 #include "at32f435_437_clock.h"
42 #include "cdc_class.h"
45 #include "drivers/time.h"
46 #include "drivers/serial.h"
47 #include "drivers/serial_usb_vcp.h"
48 #include "drivers/nvic.h"
49 #include "at32f435_437_tmr.h"
51 #define USB_TIMEOUT 50
53 static vcpPort_t vcpPort
;
55 otg_core_type otg_core_struct
;
57 #define APP_RX_DATA_SIZE 2048
58 #define APP_TX_DATA_SIZE 2048
60 #define APP_TX_BLOCK_SIZE 512
62 volatile uint8_t UserRxBuffer
[APP_RX_DATA_SIZE
];/* Received Data over USB are stored in this buffer */
63 volatile uint8_t UserTxBuffer
[APP_TX_DATA_SIZE
];/* Received Data over UART (CDC interface) are stored in this buffer */
66 /* Increment this pointer or roll it back to start address when data are received over USART */
67 volatile uint32_t UserTxBufPtrIn
= 0;
68 /* Increment this pointer or roll it back to start address when data are sent over USB */
69 volatile uint32_t UserTxBufPtrOut
= 0;
71 volatile uint32_t APP_Rx_ptr_out
= 0;
72 volatile uint32_t APP_Rx_ptr_in
= 0;
73 static uint8_t APP_Rx_Buffer
[APP_RX_DATA_SIZE
];
75 tmr_type
* usbTxTmr
= TMR20
;
76 #define CDC_POLLING_INTERVAL 5
78 static void (*ctrlLineStateCb
)(void* context
, uint16_t ctrlLineState
);
79 static void *ctrlLineStateCbContext
;
80 static void (*baudRateCb
)(void *context
, uint32_t baud
);
81 static void *baudRateCbContext
;
83 void CDC_SetBaudRateCb(void (*cb
)(void *context
, uint32_t baud
), void *context
)
85 baudRateCbContext
= context
;
89 void CDC_SetCtrlLineStateCb(void (*cb
)(void *context
, uint16_t ctrlLineState
), void *context
)
91 ctrlLineStateCbContext
= context
;
95 void usb_clock48m_select(usb_clk48_s clk_s
)
97 if(clk_s
== USB_CLK_HICK
)
99 crm_usb_clock_source_select(CRM_USB_CLOCK_SOURCE_HICK
);
100 crm_periph_clock_enable(CRM_ACC_PERIPH_CLOCK
, TRUE
);
106 acc_sof_select(ACC_SOF_OTG1
);
108 acc_sof_select(ACC_SOF_OTG2
);
110 acc_calibration_mode_enable(ACC_CAL_HICKTRIM
, TRUE
);
112 switch(system_core_clock
)
116 crm_usb_clock_div_set(CRM_USB_DIV_1
);
121 crm_usb_clock_div_set(CRM_USB_DIV_1_5
);
126 crm_usb_clock_div_set(CRM_USB_DIV_2
);
131 crm_usb_clock_div_set(CRM_USB_DIV_2_5
);
136 crm_usb_clock_div_set(CRM_USB_DIV_3
);
141 crm_usb_clock_div_set(CRM_USB_DIV_3_5
);
146 crm_usb_clock_div_set(CRM_USB_DIV_4
);
151 crm_usb_clock_div_set(CRM_USB_DIV_4_5
);
156 crm_usb_clock_div_set(CRM_USB_DIV_5
);
161 crm_usb_clock_div_set(CRM_USB_DIV_5_5
);
166 crm_usb_clock_div_set(CRM_USB_DIV_6
);
176 void usb_gpio_config(void)
178 gpio_init_type gpio_init_struct
;
180 crm_periph_clock_enable(OTG_PIN_GPIO_CLOCK
, TRUE
);
181 gpio_default_para_init(&gpio_init_struct
);
183 gpio_init_struct
.gpio_drive_strength
= GPIO_DRIVE_STRENGTH_STRONGER
;
184 gpio_init_struct
.gpio_out_type
= GPIO_OUTPUT_PUSH_PULL
;
185 gpio_init_struct
.gpio_mode
= GPIO_MODE_MUX
;
186 gpio_init_struct
.gpio_pull
= GPIO_PULL_NONE
;
188 gpio_init_struct
.gpio_pins
= OTG_PIN_DP
| OTG_PIN_DM
;
189 gpio_init(OTG_PIN_GPIO
, &gpio_init_struct
);
191 gpio_pin_mux_config(OTG_PIN_GPIO
, OTG_PIN_DP_SOURCE
, OTG_PIN_MUX
);
192 gpio_pin_mux_config(OTG_PIN_GPIO
, OTG_PIN_DM_SOURCE
, OTG_PIN_MUX
);
194 #ifdef USB_SOF_OUTPUT_ENABLE
195 crm_periph_clock_enable(OTG_PIN_SOF_GPIO_CLOCK
, TRUE
);
196 gpio_init_struct
.gpio_pins
= OTG_PIN_SOF
;
197 gpio_init(OTG_PIN_SOF_GPIO
, &gpio_init_struct
);
198 gpio_pin_mux_config(OTG_PIN_GPIO
, OTG_PIN_SOF_SOURCE
, OTG_PIN_MUX
);
201 #ifndef USB_VBUS_IGNORE
202 gpio_init_struct
.gpio_pins
= OTG_PIN_VBUS
;
203 gpio_init_struct
.gpio_pull
= GPIO_PULL_DOWN
;
204 gpio_pin_mux_config(OTG_PIN_GPIO
, OTG_PIN_VBUS_SOURCE
, OTG_PIN_MUX
);
205 gpio_init(OTG_PIN_GPIO
, &gpio_init_struct
);
209 #ifdef USB_LOW_POWER_WAKUP
210 void usb_low_power_wakeup_config(void)
212 exint_init_type exint_init_struct
;
214 crm_periph_clock_enable(CRM_SCFG_PERIPH_CLOCK
, TRUE
);
215 exint_default_para_init(&exint_init_struct
);
217 exint_init_struct
.line_enable
= TRUE
;
218 exint_init_struct
.line_mode
= EXINT_LINE_INTERRUPUT
;
219 exint_init_struct
.line_select
= OTG_WKUP_EXINT_LINE
;
220 exint_init_struct
.line_polarity
= EXINT_TRIGGER_RISING_EDGE
;
221 exint_init(&exint_init_struct
);
223 nvic_irq_enable(OTG_WKUP_IRQ
, NVIC_PRIORITY_BASE(NVIC_PRIO_USB_WUP
), NVIC_PRIORITY_SUB(NVIC_PRIO_USB_WUP
));
226 void OTG_WKUP_HANDLER(void)
228 exint_flag_clear(OTG_WKUP_EXINT_LINE
);
233 uint32_t CDC_Send_FreeBytes(void)
237 ATOMIC_BLOCK(NVIC_BUILD_PRIORITY(6, 0)) {
238 freeBytes
= ((UserTxBufPtrOut
- UserTxBufPtrIn
) + (-((int)(UserTxBufPtrOut
<= UserTxBufPtrIn
)) & APP_TX_DATA_SIZE
)) - 1;
244 uint32_t CDC_Send_DATA(const uint8_t *ptrBuffer
, uint32_t sendLength
)
246 for (uint32_t i
= 0; i
< sendLength
; i
++) {
247 while (CDC_Send_FreeBytes() == 0) {
250 ATOMIC_BLOCK(NVIC_BUILD_PRIORITY(6, 0)) {
251 UserTxBuffer
[UserTxBufPtrIn
] = ptrBuffer
[i
];
252 UserTxBufPtrIn
= (UserTxBufPtrIn
+ 1) % APP_TX_DATA_SIZE
;
258 void TxTimerConfig(void)
260 tmr_base_init(usbTxTmr
, (CDC_POLLING_INTERVAL
- 1), ((system_core_clock
)/1000 - 1));
261 tmr_clock_source_div_set(usbTxTmr
, TMR_CLOCK_DIV1
);
262 tmr_cnt_dir_set(usbTxTmr
, TMR_COUNT_UP
);
263 tmr_period_buffer_enable(usbTxTmr
, TRUE
);
264 tmr_interrupt_enable(usbTxTmr
, TMR_OVF_INT
, TRUE
);
265 nvic_irq_enable(TMR20_OVF_IRQn
, NVIC_PRIORITY_BASE(NVIC_PRIO_USB
), NVIC_PRIORITY_SUB(NVIC_PRIO_USB
));
267 tmr_counter_enable(usbTxTmr
,TRUE
);
270 void TMR20_OVF_IRQHandler(void)
273 static uint32_t lastBuffsize
= 0;
275 cdc_struct_type
*pcdc
= (cdc_struct_type
*)otg_core_struct
.dev
.class_handler
->pdata
;
277 if (pcdc
->g_tx_completed
== 1) {
279 bool needZeroLengthPacket
= lastBuffsize
% 64 == 0;
281 UserTxBufPtrOut
+= lastBuffsize
;
282 if (UserTxBufPtrOut
== APP_TX_DATA_SIZE
) {
287 if (needZeroLengthPacket
) {
288 usb_vcp_send_data(&otg_core_struct
.dev
, (uint8_t*)&UserTxBuffer
[UserTxBufPtrOut
], 0);
292 if (UserTxBufPtrOut
!= UserTxBufPtrIn
) {
293 if (UserTxBufPtrOut
> UserTxBufPtrIn
) {
294 buffsize
= APP_TX_DATA_SIZE
- UserTxBufPtrOut
;
296 buffsize
= UserTxBufPtrIn
- UserTxBufPtrOut
;
298 if (buffsize
> APP_TX_BLOCK_SIZE
) {
299 buffsize
= APP_TX_BLOCK_SIZE
;
302 uint32_t txed
= usb_vcp_send_data(&otg_core_struct
.dev
,(uint8_t*)&UserTxBuffer
[UserTxBufPtrOut
], buffsize
);
303 if (txed
== SUCCESS
) {
304 lastBuffsize
= buffsize
;
308 tmr_flag_clear(usbTxTmr
, TMR_OVF_FLAG
);
311 uint8_t usbIsConnected(void)
313 return (USB_CONN_STATE_DEFAULT
!= otg_core_struct
.dev
.conn_state
);
316 uint8_t usbIsConfigured(void)
318 return (USB_CONN_STATE_CONFIGURED
== otg_core_struct
.dev
.conn_state
);
321 uint8_t usbVcpIsConnected(void)
323 return usbIsConnected();
326 void OTG_IRQ_HANDLER(void)
328 usbd_irq_handler(&otg_core_struct
);
331 static void usbVcpSetBaudRate(serialPort_t
*instance
, uint32_t baudRate
)
337 static void usbVcpSetMode(serialPort_t
*instance
, portMode_e mode
)
343 static void usbVcpSetCtrlLineStateCb(serialPort_t
*instance
, void (*cb
)(void *context
, uint16_t ctrlLineState
), void *context
)
346 CDC_SetCtrlLineStateCb((void (*)(void *context
, uint16_t ctrlLineState
))cb
, context
);
349 static void usbVcpSetBaudRateCb(serialPort_t
*instance
, void (*cb
)(serialPort_t
*context
, uint32_t baud
), serialPort_t
*context
)
352 CDC_SetBaudRateCb((void (*)(void *context
, uint32_t baud
))cb
, (void *)context
);
355 static bool isUsbVcpTransmitBufferEmpty(const serialPort_t
*instance
)
361 static uint32_t usbVcpAvailable(const serialPort_t
*instance
)
365 uint32_t available
=0;
367 available
=APP_Rx_ptr_in
-APP_Rx_ptr_out
;
369 cdc_struct_type
*pcdc
= (cdc_struct_type
*)otg_core_struct
.dev
.class_handler
->pdata
;
370 if(pcdc
->g_rx_completed
== 1){
371 available
=pcdc
->g_rxlen
;
377 static uint8_t usbVcpRead(serialPort_t
*instance
)
381 if ((APP_Rx_ptr_in
== 0) || (APP_Rx_ptr_out
== APP_Rx_ptr_in
)){
383 APP_Rx_ptr_in
= usb_vcp_get_rxdata(&otg_core_struct
.dev
, APP_Rx_Buffer
);
384 if(APP_Rx_ptr_in
== 0) {
388 return APP_Rx_Buffer
[APP_Rx_ptr_out
++];
391 static void usbVcpWriteBuf(serialPort_t
*instance
, const void *data
, int count
)
395 if (!(usbIsConnected() && usbIsConfigured())) {
399 uint32_t start
= millis();
400 const uint8_t *p
= data
;
402 uint32_t txed
= CDC_Send_DATA(p
, count
);
406 if (millis() - start
> USB_TIMEOUT
) {
412 static bool usbVcpFlush(vcpPort_t
*port
)
414 uint32_t count
= port
->txAt
;
421 if (!usbIsConnected() || !usbIsConfigured()) {
425 uint32_t start
= millis();
426 uint8_t *p
= port
->txBuf
;
428 uint32_t txed
= CDC_Send_DATA(p
, count
);
432 if (millis() - start
> USB_TIMEOUT
) {
438 static void usbVcpWrite(serialPort_t
*instance
, uint8_t c
)
440 vcpPort_t
*port
= container_of(instance
, vcpPort_t
, port
);
442 port
->txBuf
[port
->txAt
++] = c
;
443 if (!port
->buffering
|| port
->txAt
>= ARRAYLEN(port
->txBuf
)) {
448 static void usbVcpBeginWrite(serialPort_t
*instance
)
450 vcpPort_t
*port
= container_of(instance
, vcpPort_t
, port
);
451 port
->buffering
= true;
454 static uint32_t usbTxBytesFree(const serialPort_t
*instance
)
457 return CDC_Send_FreeBytes();
460 static void usbVcpEndWrite(serialPort_t
*instance
)
462 vcpPort_t
*port
= container_of(instance
, vcpPort_t
, port
);
463 port
->buffering
= false;
467 static const struct serialPortVTable usbVTable
[] = {
469 .serialWrite
= usbVcpWrite
,
470 .serialTotalRxWaiting
= usbVcpAvailable
,
471 .serialTotalTxFree
= usbTxBytesFree
,
472 .serialRead
= usbVcpRead
,
473 .serialSetBaudRate
= usbVcpSetBaudRate
,
474 .isSerialTransmitBufferEmpty
= isUsbVcpTransmitBufferEmpty
,
475 .setMode
= usbVcpSetMode
,
476 .setCtrlLineStateCb
= usbVcpSetCtrlLineStateCb
,
477 .setBaudRateCb
= usbVcpSetBaudRateCb
,
478 .writeBuf
= usbVcpWriteBuf
,
479 .beginWrite
= usbVcpBeginWrite
,
480 .endWrite
= usbVcpEndWrite
484 serialPort_t
*usbVcpOpen(void)
488 IOInit(IOGetByTag(IO_TAG(PA11
)), OWNER_USB
, 0);
489 IOInit(IOGetByTag(IO_TAG(PA12
)), OWNER_USB
, 0);
492 #ifdef USB_LOW_POWER_WAKUP
493 usb_low_power_wakeup_config();
496 crm_periph_clock_enable(OTG_CLOCK
, TRUE
);
497 usb_clock48m_select(USB_CLK_HEXT
);
498 nvic_irq_enable(OTG_IRQ
, NVIC_PRIORITY_BASE(NVIC_PRIO_USB
), NVIC_PRIORITY_SUB(NVIC_PRIO_USB
));
500 usbGenerateDisconnectPulse();
502 usbd_init(&otg_core_struct
,
503 USB_FULL_SPEED_CORE_ID
,
508 s
->port
.vTable
= usbVTable
;
512 return (serialPort_t
*)s
;
515 uint32_t usbVcpGetBaudRate(serialPort_t
*instance
)
518 cdc_struct_type
*pcdc
= (cdc_struct_type
*)otg_core_struct
.dev
.class_handler
->pdata
;
519 return pcdc
->linecoding
.bitrate
;