Acc g scaling with DSP
[inav.git] / src / main / drivers / serial_usb_vcp_at32f43x.c
blob03e071cadb82819be5a04edd801e4762a5820484
1 /*
2 * This file is part of Cleanflight.
4 * Cleanflight is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * Cleanflight is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
16 * author : emsr (shanggl@wo.cn)
17 * hw_config is more modified and is implemented using emsr's VCP code
18 * (implemented using timers)
21 #include <stdint.h>
23 #include <stdbool.h>
25 #include "platform.h"
27 #ifdef USE_VCP
29 #include "build/build_config.h"
31 #include "common/utils.h"
32 #include "drivers/io.h"
33 #include "build/atomic.h"
35 #include "usb_conf.h"
36 #include "usb_core.h"
37 #include "usbd_int.h"
38 #include "cdc_class.h"
39 #include "cdc_desc.h"
40 #include "usb_io.h"
42 #include "drivers/time.h"
43 #include "at32f435_437_clock.h"
44 #include "serial.h"
45 #include "serial_usb_vcp_at32f43x.h"
46 #include "nvic.h"
47 #include "at32f435_437_tmr.h"
48 #include "stddef.h"
50 otg_core_type otg_core_struct;
51 #define USB_TIMEOUT 50
53 static vcpPort_t vcpPort;
55 /**
56 * @brief usb 48M clock select
57 * @param clk_s:USB_CLK_HICK, USB_CLK_HEXT
58 * @retval none
60 void usb_clock48m_select(usb_clk48_s clk_s)
62 if(clk_s == USB_CLK_HICK)
64 crm_usb_clock_source_select(CRM_USB_CLOCK_SOURCE_HICK);
66 /* enable the acc calibration ready interrupt */
67 crm_periph_clock_enable(CRM_ACC_PERIPH_CLOCK, TRUE);
69 /* update the c1\c2\c3 value */
70 acc_write_c1(7980);
71 acc_write_c2(8000);
72 acc_write_c3(8020);
73 #if (USB_ID == 0)
74 acc_sof_select(ACC_SOF_OTG1);
75 #else
76 acc_sof_select(ACC_SOF_OTG2);
77 #endif
78 /* open acc calibration */
79 acc_calibration_mode_enable(ACC_CAL_HICKTRIM, TRUE);
81 else
83 switch(system_core_clock)
85 /* 48MHz */
86 case 48000000:
87 crm_usb_clock_div_set(CRM_USB_DIV_1);
88 break;
90 /* 72MHz */
91 case 72000000:
92 crm_usb_clock_div_set(CRM_USB_DIV_1_5);
93 break;
95 /* 96MHz */
96 case 96000000:
97 crm_usb_clock_div_set(CRM_USB_DIV_2);
98 break;
100 /* 120MHz */
101 case 120000000:
102 crm_usb_clock_div_set(CRM_USB_DIV_2_5);
103 break;
105 /* 144MHz */
106 case 144000000:
107 crm_usb_clock_div_set(CRM_USB_DIV_3);
108 break;
110 /* 168MHz */
111 case 168000000:
112 crm_usb_clock_div_set(CRM_USB_DIV_3_5);
113 break;
115 /* 192MHz */
116 case 192000000:
117 crm_usb_clock_div_set(CRM_USB_DIV_4);
118 break;
120 /* 216MHz */
121 case 216000000:
122 crm_usb_clock_div_set(CRM_USB_DIV_4_5);
123 break;
125 /* 240MHz */
126 case 240000000:
127 crm_usb_clock_div_set(CRM_USB_DIV_5);
128 break;
130 /* 264MHz */
131 case 264000000:
132 crm_usb_clock_div_set(CRM_USB_DIV_5_5);
133 break;
135 /* 288MHz */
136 case 288000000:
137 crm_usb_clock_div_set(CRM_USB_DIV_6);
138 break;
140 default:
141 break;
148 * @brief this function config gpio.
149 * @param none
150 * @retval none
152 void usb_gpio_config(void)
154 gpio_init_type gpio_init_struct;
156 crm_periph_clock_enable(OTG_PIN_GPIO_CLOCK, TRUE);
157 gpio_default_para_init(&gpio_init_struct);
159 gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
160 gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
161 gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
162 gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
164 /* dp and dm */
165 gpio_init_struct.gpio_pins = OTG_PIN_DP | OTG_PIN_DM;
166 gpio_init(OTG_PIN_GPIO, &gpio_init_struct);
168 gpio_pin_mux_config(OTG_PIN_GPIO, OTG_PIN_DP_SOURCE, OTG_PIN_MUX);
169 gpio_pin_mux_config(OTG_PIN_GPIO, OTG_PIN_DM_SOURCE, OTG_PIN_MUX);
171 #ifdef USB_SOF_OUTPUT_ENABLE
172 crm_periph_clock_enable(OTG_PIN_SOF_GPIO_CLOCK, TRUE);
173 gpio_init_struct.gpio_pins = OTG_PIN_SOF;
174 gpio_init(OTG_PIN_SOF_GPIO, &gpio_init_struct);
175 gpio_pin_mux_config(OTG_PIN_GPIO, OTG_PIN_SOF_SOURCE, OTG_PIN_MUX);
176 #endif
178 /* otgfs use vbus pin */
179 #ifndef USB_VBUS_IGNORE
180 gpio_init_struct.gpio_pins = OTG_PIN_VBUS;
181 gpio_init_struct.gpio_pull = GPIO_PULL_DOWN;
182 gpio_pin_mux_config(OTG_PIN_GPIO, OTG_PIN_VBUS_SOURCE, OTG_PIN_MUX);
183 gpio_init(OTG_PIN_GPIO, &gpio_init_struct);
184 #endif
188 #ifdef USB_LOW_POWER_WAKUP
190 * @brief usb low power wakeup interrupt config
191 * @param none
192 * @retval none
194 void usb_low_power_wakeup_config(void)
196 exint_init_type exint_init_struct;
198 crm_periph_clock_enable(CRM_SCFG_PERIPH_CLOCK, TRUE);
199 exint_default_para_init(&exint_init_struct);
201 exint_init_struct.line_enable = TRUE;
202 exint_init_struct.line_mode = EXINT_LINE_INTERRUPUT;
203 exint_init_struct.line_select = OTG_WKUP_EXINT_LINE;
204 exint_init_struct.line_polarity = EXINT_TRIGGER_RISING_EDGE;
205 exint_init(&exint_init_struct);
207 nvic_irq_enable(OTG_WKUP_IRQ, NVIC_PRIO_USB_WUP,0);
211 * @brief this function handles otgfs wakup interrupt.
212 * @param none
213 * @retval none
215 void OTG_WKUP_HANDLER(void)
217 exint_flag_clear(OTG_WKUP_EXINT_LINE);
220 #endif
223 /********************************************
224 * copy from cdc part
227 uint32_t CDC_Send_FreeBytes(void)
230 return the bytes free in the circular buffer
232 functionally equivalent to:
233 (APP_Rx_ptr_out > APP_Rx_ptr_in ? APP_Rx_ptr_out - APP_Rx_ptr_in : APP_RX_DATA_SIZE - APP_Rx_ptr_in + APP_Rx_ptr_in)
234 but without the impact of the condition check.
236 uint32_t freeBytes;
237 ATOMIC_BLOCK(NVIC_PRIO_VCP) {
238 freeBytes = ((UserTxBufPtrOut - UserTxBufPtrIn) + (-((int)(UserTxBufPtrOut <= UserTxBufPtrIn)) & APP_TX_DATA_SIZE)) - 1;
241 return freeBytes;
245 * @brief CDC_Send_DATA
246 * CDC received data to be send over USB IN endpoint are managed in
247 * this function.
248 * @param ptrBuffer: Buffer of data to be sent
249 * @param sendLength: Number of data to be sent (in bytes)
250 * @retval Bytes sent
252 uint32_t CDC_Send_DATA(const uint8_t *ptrBuffer, uint32_t sendLength)
254 for (uint32_t i = 0; i < sendLength; i++) {
255 while (CDC_Send_FreeBytes() == 0) {
256 // block until there is free space in the ring buffer
257 delay(1);
260 ATOMIC_BLOCK(NVIC_PRIO_VCP) {
261 UserTxBuffer[UserTxBufPtrIn] = ptrBuffer[i];
262 UserTxBufPtrIn = (UserTxBufPtrIn + 1) % APP_TX_DATA_SIZE;
265 return sendLength;
268 void TxTimerConfig(void){
269 /* Initialize TIMx peripheral as follow:
270 + Period = CDC_POLLING_INTERVAL*1000 - 1 every 5ms
271 + Prescaler = ((SystemCoreClock/2)/10000) - 1
272 + ClockDivision = 0
273 + Counter direction = Up
275 crm_periph_clock_enable(CRM_TMR20_PERIPH_CLOCK, TRUE);
276 //timer, period, perscaler
277 tmr_base_init(usbTxTmr,(CDC_POLLING_INTERVAL - 1),((system_core_clock)/10000 - 1));
278 //TMR_CLOCK_DIV1 = 0X00 NO DIV
279 tmr_clock_source_div_set(usbTxTmr,TMR_CLOCK_DIV1);
280 //COUNT UP
281 tmr_cnt_dir_set(usbTxTmr,TMR_COUNT_UP);
283 tmr_period_buffer_enable(usbTxTmr,TRUE);
285 tmr_interrupt_enable(usbTxTmr, TMR_OVF_INT, TRUE);
287 nvic_irq_enable(TMR20_OVF_IRQn,NVIC_PRIO_USB,0);
289 tmr_counter_enable(usbTxTmr,TRUE);
294 * @brief TIM period elapsed callback
295 * @param htim: TIM handle
296 * @retval None
298 void TMR20_OVF_IRQHandler(void)
301 uint32_t buffsize;
302 static uint32_t lastBuffsize = 0;
304 cdc_struct_type *pcdc = (cdc_struct_type *)otg_core_struct.dev.class_handler->pdata;
306 if (pcdc->g_tx_completed == 1) {
307 // endpoint has finished transmitting previous block
308 if (lastBuffsize) {
309 bool needZeroLengthPacket = lastBuffsize % 64 == 0;
311 // move the ring buffer tail based on the previous succesful transmission
312 UserTxBufPtrOut += lastBuffsize;
313 if (UserTxBufPtrOut == APP_TX_DATA_SIZE) {
314 UserTxBufPtrOut = 0;
316 lastBuffsize = 0;
318 if (needZeroLengthPacket) {
319 usb_vcp_send_data(&otg_core_struct.dev, (uint8_t*)&UserTxBuffer[UserTxBufPtrOut], 0);
320 return;
323 if (UserTxBufPtrOut != UserTxBufPtrIn) {
324 if (UserTxBufPtrOut > UserTxBufPtrIn) { /* Roll-back */
325 buffsize = APP_TX_DATA_SIZE - UserTxBufPtrOut;
326 } else {
327 buffsize = UserTxBufPtrIn - UserTxBufPtrOut;
329 if (buffsize > APP_TX_BLOCK_SIZE) {
330 buffsize = APP_TX_BLOCK_SIZE;
333 uint32_t txed=usb_vcp_send_data(&otg_core_struct.dev,(uint8_t*)&UserTxBuffer[UserTxBufPtrOut], buffsize);
334 if (txed==SUCCESS) {
335 lastBuffsize = buffsize;
339 tmr_flag_clear(usbTxTmr,TMR_OVF_FLAG);
342 /************************************************************/
344 uint8_t usbIsConnected(void){
345 return (USB_CONN_STATE_DEFAULT !=otg_core_struct.dev.conn_state);
348 uint8_t usbIsConfigured(void){
349 return (USB_CONN_STATE_CONFIGURED ==otg_core_struct.dev.conn_state);
352 bool usbVcpIsConnected(const serialPort_t *instance)
354 (void)instance;
355 return usbIsConnected() && usbIsConfigured();
359 * @brief this function handles otgfs interrupt.
360 * @param none
361 * @retval none
363 void OTG_IRQ_HANDLER(void)
365 usbd_irq_handler(&otg_core_struct);
369 static void usbVcpSetBaudRate(serialPort_t *instance, uint32_t baudRate)
371 UNUSED(instance);
372 UNUSED(baudRate);
375 static void usbVcpSetMode(serialPort_t *instance, portMode_t mode)
377 UNUSED(instance);
378 UNUSED(mode);
381 static bool isUsbVcpTransmitBufferEmpty(const serialPort_t *instance)
383 UNUSED(instance);
384 return true;
387 static uint32_t usbVcpAvailable(const serialPort_t *instance)
389 UNUSED(instance);
390 uint32_t available=0;
392 available=APP_Rx_ptr_in-APP_Rx_ptr_out;
393 if(available ==0){
394 // check anything that hasn't been copied into the cache
395 cdc_struct_type *pcdc = (cdc_struct_type *)otg_core_struct.dev.class_handler->pdata;
396 if(pcdc->g_rx_completed == 1){
397 available=pcdc->g_rxlen;
400 return available;
403 static uint8_t usbVcpRead(serialPort_t *instance)
405 UNUSED(instance);
407 // Check the cache is empty. If empty, add a read
408 if ((APP_Rx_ptr_in==0)||(APP_Rx_ptr_out == APP_Rx_ptr_in)){
409 APP_Rx_ptr_out=0;
410 APP_Rx_ptr_in=usb_vcp_get_rxdata(&otg_core_struct.dev,APP_Rx_Buffer);// usb Maximum 64 bytes each time
411 if(APP_Rx_ptr_in==0)
413 // No data is read, return 0
414 return 0;
417 return APP_Rx_Buffer[APP_Rx_ptr_out++];
420 // Write buffer data to vpc
421 static void usbVcpWriteBuf(serialPort_t *instance, const void *data, int count)
423 UNUSED(instance);
425 if (!usbVcpIsConnected(instance)) {
426 return;
429 uint32_t start = millis();
430 const uint8_t *p = data;
431 while (count > 0) {
432 uint32_t txed = CDC_Send_DATA(p, count);
433 count -= txed;
434 p += txed;
436 if (millis() - start > USB_TIMEOUT) {
437 break;
442 static bool usbVcpFlush(vcpPort_t *port)
444 uint32_t count = port->txAt;
445 port->txAt = 0;
447 if (count == 0) {
448 return true;
451 if (!usbIsConnected() || !usbIsConfigured()) {
452 return false;
455 uint32_t start = millis();
456 uint8_t *p = port->txBuf;
457 while (count > 0) {
458 uint32_t txed = CDC_Send_DATA(p, count);
459 count -= txed;
460 p += txed;
462 if (millis() - start > USB_TIMEOUT) {
463 break;
466 return count == 0;
469 static void usbVcpWrite(serialPort_t *instance, uint8_t c)
471 vcpPort_t *port = container_of(instance, vcpPort_t, port);
473 port->txBuf[port->txAt++] = c;
474 if (!port->buffering || port->txAt >= ARRAYLEN(port->txBuf)) {
475 usbVcpFlush(port);
479 static void usbVcpBeginWrite(serialPort_t *instance)
481 vcpPort_t *port = container_of(instance, vcpPort_t, port);
482 port->buffering = true;
485 static uint32_t usbTxBytesFree(const serialPort_t *instance)
487 UNUSED(instance);
488 return CDC_Send_FreeBytes();
491 static void usbVcpEndWrite(serialPort_t *instance)
493 vcpPort_t *port = container_of(instance, vcpPort_t, port);
494 port->buffering = false;
495 usbVcpFlush(port);
498 static const struct serialPortVTable usbVTable[] = {
500 .serialWrite = usbVcpWrite,
501 .serialTotalRxWaiting = usbVcpAvailable,
502 .serialTotalTxFree = usbTxBytesFree,
503 .serialRead = usbVcpRead,
504 .serialSetBaudRate = usbVcpSetBaudRate,
505 .isSerialTransmitBufferEmpty = isUsbVcpTransmitBufferEmpty,
506 .setMode = usbVcpSetMode,
507 .isConnected = usbVcpIsConnected,
508 .writeBuf = usbVcpWriteBuf,
509 .beginWrite = usbVcpBeginWrite,
510 .endWrite = usbVcpEndWrite,
511 .isIdle = NULL,
515 void usbVcpInitHardware(void)
517 IOInit(IOGetByTag(IO_TAG(PA11)), OWNER_USB, RESOURCE_INPUT, 0);
518 IOInit(IOGetByTag(IO_TAG(PA12)), OWNER_USB, RESOURCE_OUTPUT, 0);
520 /* usb gpio config */
521 usb_gpio_config();
523 #ifdef USB_LOW_POWER_WAKUP
524 usb_low_power_wakeup_config();
525 #endif
527 /* enable otgfs clock */
528 crm_periph_clock_enable(OTG_CLOCK, TRUE);
530 /* select usb 48m clcok source */
531 usb_clock48m_select(USB_CLK_HEXT);
533 /* enable otgfs irq,cannot set too high priority */
534 nvic_irq_enable(OTG_IRQ,NVIC_PRIO_USB,0);
536 usbGenerateDisconnectPulse();
538 /* init usb */
539 usbd_init(&otg_core_struct,
540 USB_FULL_SPEED_CORE_ID,
541 USB_ID,
542 &cdc_class_handler,
543 &cdc_desc_handler);
545 //config TX timer
546 TxTimerConfig();
549 serialPort_t *usbVcpOpen(void)
551 vcpPort_t *s;
552 s = &vcpPort;
553 s->port.vTable = usbVTable;
555 return (serialPort_t *)s;
558 uint32_t usbVcpGetBaudRate(serialPort_t *instance)
560 UNUSED(instance);
561 cdc_struct_type *pcdc = (cdc_struct_type *)otg_core_struct.dev.class_handler->pdata;
562 return pcdc->linecoding.bitrate;
563 // return CDC_BaudRate();
566 #endif