Send motor data and then immediately decode prior telemetry data for bitbanged DSHOT...
[betaflight.git] / src / main / drivers / at32 / serial_usb_vcp_at32f4.c
blob67a789149bb16b87f3f2cee44dd34f041a39acc8
1 /*
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)
8 * any later version.
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/>.
21 #include <stdint.h>
22 #include <stdbool.h>
24 #include "platform.h"
26 #ifdef USE_VCP
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"
36 #include "pg/usb.h"
38 #include "at32f435_437_clock.h"
39 #include "usb_conf.h"
40 #include "usb_core.h"
41 #include "usbd_int.h"
42 #include "cdc_class.h"
43 #include "cdc_desc.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 */
64 uint32_t BuffLength;
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;
86 baudRateCb = cb;
89 void CDC_SetCtrlLineStateCb(void (*cb)(void *context, uint16_t ctrlLineState), void *context)
91 ctrlLineStateCbContext = context;
92 ctrlLineStateCb = cb;
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);
102 acc_write_c1(7980);
103 acc_write_c2(8000);
104 acc_write_c3(8020);
105 #if (USB_ID == 0)
106 acc_sof_select(ACC_SOF_OTG1);
107 #else
108 acc_sof_select(ACC_SOF_OTG2);
109 #endif
110 acc_calibration_mode_enable(ACC_CAL_HICKTRIM, TRUE);
111 } else {
112 switch(system_core_clock)
114 /* 48MHz */
115 case 48000000:
116 crm_usb_clock_div_set(CRM_USB_DIV_1);
117 break;
119 /* 72MHz */
120 case 72000000:
121 crm_usb_clock_div_set(CRM_USB_DIV_1_5);
122 break;
124 /* 96MHz */
125 case 96000000:
126 crm_usb_clock_div_set(CRM_USB_DIV_2);
127 break;
129 /* 120MHz */
130 case 120000000:
131 crm_usb_clock_div_set(CRM_USB_DIV_2_5);
132 break;
134 /* 144MHz */
135 case 144000000:
136 crm_usb_clock_div_set(CRM_USB_DIV_3);
137 break;
139 /* 168MHz */
140 case 168000000:
141 crm_usb_clock_div_set(CRM_USB_DIV_3_5);
142 break;
144 /* 192MHz */
145 case 192000000:
146 crm_usb_clock_div_set(CRM_USB_DIV_4);
147 break;
149 /* 216MHz */
150 case 216000000:
151 crm_usb_clock_div_set(CRM_USB_DIV_4_5);
152 break;
154 /* 240MHz */
155 case 240000000:
156 crm_usb_clock_div_set(CRM_USB_DIV_5);
157 break;
159 /* 264MHz */
160 case 264000000:
161 crm_usb_clock_div_set(CRM_USB_DIV_5_5);
162 break;
164 /* 288MHz */
165 case 288000000:
166 crm_usb_clock_div_set(CRM_USB_DIV_6);
167 break;
169 default:
170 break;
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);
199 #endif
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);
206 #endif
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);
231 #endif
233 uint32_t CDC_Send_FreeBytes(void)
235 uint32_t freeBytes;
237 ATOMIC_BLOCK(NVIC_BUILD_PRIORITY(6, 0)) {
238 freeBytes = ((UserTxBufPtrOut - UserTxBufPtrIn) + (-((int)(UserTxBufPtrOut <= UserTxBufPtrIn)) & APP_TX_DATA_SIZE)) - 1;
241 return freeBytes;
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) {
248 delay(1);
250 ATOMIC_BLOCK(NVIC_BUILD_PRIORITY(6, 0)) {
251 UserTxBuffer[UserTxBufPtrIn] = ptrBuffer[i];
252 UserTxBufPtrIn = (UserTxBufPtrIn + 1) % APP_TX_DATA_SIZE;
255 return sendLength;
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)
272 uint32_t buffsize;
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) {
278 if (lastBuffsize) {
279 bool needZeroLengthPacket = lastBuffsize % 64 == 0;
281 UserTxBufPtrOut += lastBuffsize;
282 if (UserTxBufPtrOut == APP_TX_DATA_SIZE) {
283 UserTxBufPtrOut = 0;
285 lastBuffsize = 0;
287 if (needZeroLengthPacket) {
288 usb_vcp_send_data(&otg_core_struct.dev, (uint8_t*)&UserTxBuffer[UserTxBufPtrOut], 0);
289 return;
292 if (UserTxBufPtrOut != UserTxBufPtrIn) {
293 if (UserTxBufPtrOut > UserTxBufPtrIn) {
294 buffsize = APP_TX_DATA_SIZE - UserTxBufPtrOut;
295 } else {
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)
333 UNUSED(instance);
334 UNUSED(baudRate);
337 static void usbVcpSetMode(serialPort_t *instance, portMode_e mode)
339 UNUSED(instance);
340 UNUSED(mode);
343 static void usbVcpSetCtrlLineStateCb(serialPort_t *instance, void (*cb)(void *context, uint16_t ctrlLineState), void *context)
345 UNUSED(instance);
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)
351 UNUSED(instance);
352 CDC_SetBaudRateCb((void (*)(void *context, uint32_t baud))cb, (void *)context);
355 static bool isUsbVcpTransmitBufferEmpty(const serialPort_t *instance)
357 UNUSED(instance);
358 return true;
361 static uint32_t usbVcpAvailable(const serialPort_t *instance)
363 UNUSED(instance);
365 uint32_t available=0;
367 available=APP_Rx_ptr_in-APP_Rx_ptr_out;
368 if(available == 0){
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;
374 return available;
377 static uint8_t usbVcpRead(serialPort_t *instance)
379 UNUSED(instance);
381 if ((APP_Rx_ptr_in == 0) || (APP_Rx_ptr_out == APP_Rx_ptr_in)){
382 APP_Rx_ptr_out = 0;
383 APP_Rx_ptr_in = usb_vcp_get_rxdata(&otg_core_struct.dev, APP_Rx_Buffer);
384 if(APP_Rx_ptr_in == 0) {
385 return 0;
388 return APP_Rx_Buffer[APP_Rx_ptr_out++];
391 static void usbVcpWriteBuf(serialPort_t *instance, const void *data, int count)
393 UNUSED(instance);
395 if (!(usbIsConnected() && usbIsConfigured())) {
396 return;
399 uint32_t start = millis();
400 const uint8_t *p = data;
401 while (count > 0) {
402 uint32_t txed = CDC_Send_DATA(p, count);
403 count -= txed;
404 p += txed;
406 if (millis() - start > USB_TIMEOUT) {
407 break;
412 static bool usbVcpFlush(vcpPort_t *port)
414 uint32_t count = port->txAt;
415 port->txAt = 0;
417 if (count == 0) {
418 return true;
421 if (!usbIsConnected() || !usbIsConfigured()) {
422 return false;
425 uint32_t start = millis();
426 uint8_t *p = port->txBuf;
427 while (count > 0) {
428 uint32_t txed = CDC_Send_DATA(p, count);
429 count -= txed;
430 p += txed;
432 if (millis() - start > USB_TIMEOUT) {
433 break;
436 return count == 0;
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)) {
444 usbVcpFlush(port);
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)
456 UNUSED(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;
464 usbVcpFlush(port);
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)
486 vcpPort_t *s;
488 IOInit(IOGetByTag(IO_TAG(PA11)), OWNER_USB, 0);
489 IOInit(IOGetByTag(IO_TAG(PA12)), OWNER_USB, 0);
490 usb_gpio_config();
492 #ifdef USB_LOW_POWER_WAKUP
493 usb_low_power_wakeup_config();
494 #endif
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,
504 USB_ID,
505 &cdc_class_handler,
506 &cdc_desc_handler);
507 s = &vcpPort;
508 s->port.vTable = usbVTable;
510 TxTimerConfig();
512 return (serialPort_t *)s;
515 uint32_t usbVcpGetBaudRate(serialPort_t *instance)
517 UNUSED(instance);
518 cdc_struct_type *pcdc = (cdc_struct_type *)otg_core_struct.dev.class_handler->pdata;
519 return pcdc->linecoding.bitrate;
522 #endif