LP-602 significant change to USB layer. force complete USB stack reset on replug...
[librepilot.git] / flight / pios / stm32f4xx / pios_usart.c
blobfef3165ddf7dd59519b8e1035068fa1f7c8d43dc
1 /**
2 ******************************************************************************
3 * @addtogroup PIOS PIOS Core hardware abstraction layer
4 * @{
5 * @addtogroup PIOS_USART USART Functions
6 * @brief PIOS interface for USART port
7 * @{
9 * @file pios_usart.c
10 * @author The LibrePilot Project, http://www.librepilot.org, Copyright (c) 2016-2017.
11 * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
12 * @brief USART commands. Inits USARTs, controls USARTs & Interupt handlers. (STM32 dependent)
13 * @see The GNU Public License (GPL) Version 3
15 *****************************************************************************/
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 3 of the License, or
20 * (at your option) any later version.
22 * This program is distributed in the hope that it will be useful, but
23 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
24 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
25 * for more details.
27 * You should have received a copy of the GNU General Public License along
28 * with this program; if not, write to the Free Software Foundation, Inc.,
29 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
33 * @todo This is virtually identical to the F1xx driver and should be merged.
36 #include "pios.h"
38 #ifdef PIOS_INCLUDE_USART
40 #include <pios_usart_priv.h>
42 /* Provide a COM driver */
43 static void PIOS_USART_ChangeBaud(uint32_t usart_id, uint32_t baud);
44 static void PIOS_USART_ChangeConfig(uint32_t usart_id, enum PIOS_COM_Word_Length word_len, enum PIOS_COM_Parity parity, enum PIOS_COM_StopBits stop_bits, uint32_t baud_rate);
45 static void PIOS_USART_SetCtrlLine(uint32_t usart_id, uint32_t mask, uint32_t state);
46 static void PIOS_USART_RegisterRxCallback(uint32_t usart_id, pios_com_callback rx_in_cb, uint32_t context);
47 static void PIOS_USART_RegisterTxCallback(uint32_t usart_id, pios_com_callback tx_out_cb, uint32_t context);
48 static void PIOS_USART_TxStart(uint32_t usart_id, uint16_t tx_bytes_avail);
49 static void PIOS_USART_RxStart(uint32_t usart_id, uint16_t rx_bytes_avail);
50 static int32_t PIOS_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param);
52 const struct pios_com_driver pios_usart_com_driver = {
53 .set_baud = PIOS_USART_ChangeBaud,
54 .set_config = PIOS_USART_ChangeConfig,
55 .set_ctrl_line = PIOS_USART_SetCtrlLine,
56 .tx_start = PIOS_USART_TxStart,
57 .rx_start = PIOS_USART_RxStart,
58 .bind_tx_cb = PIOS_USART_RegisterTxCallback,
59 .bind_rx_cb = PIOS_USART_RegisterRxCallback,
60 .ioctl = PIOS_USART_Ioctl,
63 enum pios_usart_dev_magic {
64 PIOS_USART_DEV_MAGIC = 0x4152834A,
67 struct pios_usart_dev {
68 enum pios_usart_dev_magic magic;
69 const struct pios_usart_cfg *cfg;
70 USART_InitTypeDef init;
71 pios_com_callback rx_in_cb;
72 uint32_t rx_in_context;
73 pios_com_callback tx_out_cb;
74 uint32_t tx_out_context;
75 bool config_locked;
76 uint8_t irq_channel;
79 static bool PIOS_USART_validate(struct pios_usart_dev *usart_dev)
81 return usart_dev->magic == PIOS_USART_DEV_MAGIC;
84 const struct pios_usart_cfg *PIOS_USART_GetConfig(uint32_t usart_id)
86 struct pios_usart_dev *usart_dev = (struct pios_usart_dev *)usart_id;
88 bool valid = PIOS_USART_validate(usart_dev);
90 PIOS_Assert(valid);
92 return usart_dev->cfg;
95 static int32_t PIOS_USART_SetIrqPrio(struct pios_usart_dev *usart_dev, uint8_t irq_prio)
97 NVIC_InitTypeDef init = {
98 .NVIC_IRQChannel = usart_dev->irq_channel,
99 .NVIC_IRQChannelPreemptionPriority = irq_prio,
100 .NVIC_IRQChannelCmd = ENABLE,
103 NVIC_Init(&init);
105 return 0;
108 #if defined(PIOS_INCLUDE_FREERTOS)
109 static struct pios_usart_dev *PIOS_USART_alloc(void)
111 struct pios_usart_dev *usart_dev;
113 usart_dev = (struct pios_usart_dev *)pios_malloc(sizeof(struct pios_usart_dev));
114 if (!usart_dev) {
115 return NULL;
118 memset(usart_dev, 0, sizeof(struct pios_usart_dev));
119 usart_dev->magic = PIOS_USART_DEV_MAGIC;
120 return usart_dev;
122 #else
123 static struct pios_usart_dev pios_usart_devs[PIOS_USART_MAX_DEVS];
124 static uint8_t pios_usart_num_devs;
125 static struct pios_usart_dev *PIOS_USART_alloc(void)
127 struct pios_usart_dev *usart_dev;
129 if (pios_usart_num_devs >= PIOS_USART_MAX_DEVS) {
130 return NULL;
133 usart_dev = &pios_usart_devs[pios_usart_num_devs++];
135 memset(usart_dev, 0, sizeof(struct pios_usart_dev));
136 usart_dev->magic = PIOS_USART_DEV_MAGIC;
138 return usart_dev;
140 #endif /* if defined(PIOS_INCLUDE_FREERTOS) */
142 /* Bind Interrupt Handlers
144 * Map all valid USART IRQs to the common interrupt handler
145 * and provide storage for a 32-bit device id IRQ to map
146 * each physical IRQ to a specific registered device instance.
148 static void PIOS_USART_generic_irq_handler(uint32_t usart_id);
150 static uint32_t PIOS_USART_1_id;
151 void USART1_IRQHandler(void) __attribute__((alias("PIOS_USART_1_irq_handler")));
152 static void PIOS_USART_1_irq_handler(void)
154 PIOS_USART_generic_irq_handler(PIOS_USART_1_id);
157 static uint32_t PIOS_USART_2_id;
158 void USART2_IRQHandler(void) __attribute__((alias("PIOS_USART_2_irq_handler")));
159 static void PIOS_USART_2_irq_handler(void)
161 PIOS_USART_generic_irq_handler(PIOS_USART_2_id);
164 static uint32_t PIOS_USART_3_id;
165 void USART3_IRQHandler(void) __attribute__((alias("PIOS_USART_3_irq_handler")));
166 static void PIOS_USART_3_irq_handler(void)
168 PIOS_USART_generic_irq_handler(PIOS_USART_3_id);
171 static uint32_t PIOS_USART_4_id;
172 void USART4_IRQHandler(void) __attribute__((alias("PIOS_USART_4_irq_handler")));
173 static void PIOS_USART_4_irq_handler(void)
175 PIOS_USART_generic_irq_handler(PIOS_USART_4_id);
178 static uint32_t PIOS_USART_5_id;
179 void USART5_IRQHandler(void) __attribute__((alias("PIOS_USART_5_irq_handler")));
180 static void PIOS_USART_5_irq_handler(void)
182 PIOS_USART_generic_irq_handler(PIOS_USART_5_id);
185 static uint32_t PIOS_USART_6_id;
186 void USART6_IRQHandler(void) __attribute__((alias("PIOS_USART_6_irq_handler")));
187 static void PIOS_USART_6_irq_handler(void)
189 PIOS_USART_generic_irq_handler(PIOS_USART_6_id);
193 * Initialise a single USART device
195 int32_t PIOS_USART_Init(uint32_t *usart_id, const struct pios_usart_cfg *cfg)
197 PIOS_DEBUG_Assert(usart_id);
198 PIOS_DEBUG_Assert(cfg);
200 uint32_t *local_id;
201 uint8_t irq_channel;
203 switch ((uint32_t)cfg->regs) {
204 case (uint32_t)USART1:
205 local_id = &PIOS_USART_1_id;
206 irq_channel = USART1_IRQn;
207 break;
208 case (uint32_t)USART2:
209 local_id = &PIOS_USART_2_id;
210 irq_channel = USART2_IRQn;
211 break;
212 #if !defined(STM32F411xE)
213 case (uint32_t)USART3:
214 local_id = &PIOS_USART_3_id;
215 irq_channel = USART3_IRQn;
216 break;
217 case (uint32_t)UART4:
218 local_id = &PIOS_USART_4_id;
219 irq_channel = UART4_IRQn;
220 break;
221 case (uint32_t)UART5:
222 local_id = &PIOS_USART_5_id;
223 irq_channel = UART5_IRQn;
224 break;
225 #endif /* STM32F411xE */
226 case (uint32_t)USART6:
227 local_id = &PIOS_USART_6_id;
228 irq_channel = USART6_IRQn;
229 break;
230 default:
231 goto out_fail;
234 if (*local_id) {
235 /* this port is already open */
236 *usart_id = *local_id;
237 return 0;
240 struct pios_usart_dev *usart_dev;
242 usart_dev = (struct pios_usart_dev *)PIOS_USART_alloc();
243 if (!usart_dev) {
244 goto out_fail;
247 /* Bind the configuration to the device instance */
248 usart_dev->cfg = cfg;
249 usart_dev->irq_channel = irq_channel;
251 /* Initialize the comm parameter structure */
252 USART_StructInit(&usart_dev->init); // 9600 8n1
254 /* We will set modes later, depending on installed callbacks */
255 usart_dev->init.USART_Mode = 0;
258 /* If a DTR line is specified, initialize it */
259 if (usart_dev->cfg->dtr.gpio) {
260 GPIO_Init(usart_dev->cfg->dtr.gpio, (GPIO_InitTypeDef *)&usart_dev->cfg->dtr.init);
261 PIOS_USART_SetCtrlLine((uint32_t)usart_dev, COM_CTRL_LINE_DTR_MASK, 0);
263 #ifdef PIOS_USART_INVERTER_PORT
264 /* Initialize inverter gpio and set it to off */
265 if (usart_dev->cfg->regs == PIOS_USART_INVERTER_PORT) {
266 GPIO_InitTypeDef inverterGPIOInit = {
267 .GPIO_Pin = PIOS_USART_INVERTER_PIN,
268 .GPIO_Speed = GPIO_Speed_2MHz,
269 .GPIO_Mode = GPIO_Mode_OUT,
270 .GPIO_OType = GPIO_OType_PP,
271 .GPIO_PuPd = GPIO_PuPd_UP
273 GPIO_Init(PIOS_USART_INVERTER_GPIO, &inverterGPIOInit);
275 GPIO_WriteBit(PIOS_USART_INVERTER_GPIO,
276 PIOS_USART_INVERTER_PIN,
277 PIOS_USART_INVERTER_DISABLE);
279 #endif
281 *usart_id = (uint32_t)usart_dev;
282 *local_id = (uint32_t)usart_dev;
284 PIOS_USART_SetIrqPrio(usart_dev, PIOS_IRQ_PRIO_MID);
286 return 0;
288 out_fail:
289 return -1;
292 static void PIOS_USART_Setup(struct pios_usart_dev *usart_dev)
294 /* Configure RX GPIO */
295 if ((usart_dev->init.USART_Mode & USART_Mode_Rx) && (usart_dev->cfg->rx.gpio)) {
296 if (usart_dev->cfg->remap) {
297 GPIO_PinAFConfig(usart_dev->cfg->rx.gpio,
298 __builtin_ctz(usart_dev->cfg->rx.init.GPIO_Pin),
299 usart_dev->cfg->remap);
302 GPIO_Init(usart_dev->cfg->rx.gpio, (GPIO_InitTypeDef *)&usart_dev->cfg->rx.init);
304 /* just enable RX right away, cause rcvr modules do not call rx_start method */
305 USART_ITConfig(usart_dev->cfg->regs, USART_IT_RXNE, ENABLE);
308 /* Configure TX GPIO */
309 if ((usart_dev->init.USART_Mode & USART_Mode_Tx) && usart_dev->cfg->tx.gpio) {
310 if (usart_dev->cfg->remap) {
311 GPIO_PinAFConfig(usart_dev->cfg->tx.gpio,
312 __builtin_ctz(usart_dev->cfg->tx.init.GPIO_Pin),
313 usart_dev->cfg->remap);
316 GPIO_Init(usart_dev->cfg->tx.gpio, (GPIO_InitTypeDef *)&usart_dev->cfg->tx.init);
319 /* Write new configuration */
320 { // fix parity stuff
321 USART_InitTypeDef init = usart_dev->init;
323 if ((init.USART_Parity != USART_Parity_No) && (init.USART_WordLength == USART_WordLength_8b)) {
324 init.USART_WordLength = USART_WordLength_9b;
327 USART_Init(usart_dev->cfg->regs, &init);
331 * Re enable USART.
333 USART_Cmd(usart_dev->cfg->regs, ENABLE);
336 static void PIOS_USART_RxStart(uint32_t usart_id, __attribute__((unused)) uint16_t rx_bytes_avail)
338 struct pios_usart_dev *usart_dev = (struct pios_usart_dev *)usart_id;
340 bool valid = PIOS_USART_validate(usart_dev);
342 PIOS_Assert(valid);
344 USART_ITConfig(usart_dev->cfg->regs, USART_IT_RXNE, ENABLE);
346 static void PIOS_USART_TxStart(uint32_t usart_id, __attribute__((unused)) uint16_t tx_bytes_avail)
348 struct pios_usart_dev *usart_dev = (struct pios_usart_dev *)usart_id;
350 bool valid = PIOS_USART_validate(usart_dev);
352 PIOS_Assert(valid);
354 USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, ENABLE);
358 * Changes the baud rate of the USART peripheral without re-initialising.
359 * \param[in] usart_id USART name (GPS, TELEM, AUX)
360 * \param[in] baud Requested baud rate
362 static void PIOS_USART_ChangeBaud(uint32_t usart_id, uint32_t baud)
364 struct pios_usart_dev *usart_dev = (struct pios_usart_dev *)usart_id;
366 bool valid = PIOS_USART_validate(usart_dev);
368 PIOS_Assert(valid);
370 if (usart_dev->config_locked) {
371 return;
374 /* Use our working copy of the usart init structure */
375 usart_dev->init.USART_BaudRate = baud;
377 PIOS_USART_Setup(usart_dev);
381 * Changes configuration of the USART peripheral without re-initialising.
382 * \param[in] usart_id USART name (GPS, TELEM, AUX)
383 * \param[in] word_len Requested word length
384 * \param[in] stop_bits Requested stop bits
385 * \param[in] parity Requested parity
386 * \param[in] baud_rate Requested baud rate
387 * \param[in] mode Requested mode
390 static void PIOS_USART_ChangeConfig(uint32_t usart_id,
391 enum PIOS_COM_Word_Length word_len,
392 enum PIOS_COM_Parity parity,
393 enum PIOS_COM_StopBits stop_bits,
394 uint32_t baud_rate)
396 struct pios_usart_dev *usart_dev = (struct pios_usart_dev *)usart_id;
398 bool valid = PIOS_USART_validate(usart_dev);
400 PIOS_Assert(valid);
402 if (usart_dev->config_locked) {
403 return;
406 switch (word_len) {
407 case PIOS_COM_Word_length_8b:
408 usart_dev->init.USART_WordLength = USART_WordLength_8b;
409 break;
410 case PIOS_COM_Word_length_9b:
411 usart_dev->init.USART_WordLength = USART_WordLength_9b;
412 break;
413 default:
414 break;
417 switch (stop_bits) {
418 case PIOS_COM_StopBits_0_5:
419 usart_dev->init.USART_StopBits = USART_StopBits_0_5;
420 break;
421 case PIOS_COM_StopBits_1:
422 usart_dev->init.USART_StopBits = USART_StopBits_1;
423 break;
424 case PIOS_COM_StopBits_1_5:
425 usart_dev->init.USART_StopBits = USART_StopBits_1_5;
426 break;
427 case PIOS_COM_StopBits_2:
428 usart_dev->init.USART_StopBits = USART_StopBits_2;
429 break;
430 default:
431 break;
434 switch (parity) {
435 case PIOS_COM_Parity_No:
436 usart_dev->init.USART_Parity = USART_Parity_No;
437 break;
438 case PIOS_COM_Parity_Even:
439 usart_dev->init.USART_Parity = USART_Parity_Even;
440 break;
441 case PIOS_COM_Parity_Odd:
442 usart_dev->init.USART_Parity = USART_Parity_Odd;
443 break;
444 default:
445 break;
448 if (baud_rate) {
449 usart_dev->init.USART_BaudRate = baud_rate;
452 PIOS_USART_Setup(usart_dev);
455 static void PIOS_USART_SetCtrlLine(uint32_t usart_id, uint32_t mask, uint32_t state)
457 struct pios_usart_dev *usart_dev = (struct pios_usart_dev *)usart_id;
459 bool valid = PIOS_USART_validate(usart_dev);
461 PIOS_Assert(valid);
463 /* Only attempt to drive DTR if this USART has a GPIO line defined */
464 if (usart_dev->cfg->dtr.gpio && (mask & COM_CTRL_LINE_DTR_MASK)) {
465 GPIO_WriteBit(usart_dev->cfg->dtr.gpio,
466 usart_dev->cfg->dtr.init.GPIO_Pin,
467 state & COM_CTRL_LINE_DTR_MASK ? Bit_RESET : Bit_SET);
471 static void PIOS_USART_RegisterRxCallback(uint32_t usart_id, pios_com_callback rx_in_cb, uint32_t context)
473 struct pios_usart_dev *usart_dev = (struct pios_usart_dev *)usart_id;
475 bool valid = PIOS_USART_validate(usart_dev);
477 PIOS_Assert(valid);
480 * Order is important in these assignments since ISR uses _cb
481 * field to determine if it's ok to dereference _cb and _context
483 usart_dev->rx_in_context = context;
484 usart_dev->rx_in_cb = rx_in_cb;
486 usart_dev->init.USART_Mode |= USART_Mode_Rx;
488 PIOS_USART_Setup(usart_dev);
491 static void PIOS_USART_RegisterTxCallback(uint32_t usart_id, pios_com_callback tx_out_cb, uint32_t context)
493 struct pios_usart_dev *usart_dev = (struct pios_usart_dev *)usart_id;
495 bool valid = PIOS_USART_validate(usart_dev);
497 PIOS_Assert(valid);
500 * Order is important in these assignments since ISR uses _cb
501 * field to determine if it's ok to dereference _cb and _context
503 usart_dev->tx_out_context = context;
504 usart_dev->tx_out_cb = tx_out_cb;
506 usart_dev->init.USART_Mode |= USART_Mode_Tx;
508 PIOS_USART_Setup(usart_dev);
511 static void PIOS_USART_generic_irq_handler(uint32_t usart_id)
513 struct pios_usart_dev *usart_dev = (struct pios_usart_dev *)usart_id;
515 bool valid = PIOS_USART_validate(usart_dev);
517 PIOS_Assert(valid);
519 /* Force read of dr after sr to make sure to clear error flags */
520 volatile uint16_t sr = usart_dev->cfg->regs->SR;
521 volatile uint8_t dr = usart_dev->cfg->regs->DR;
523 /* Check if RXNE flag is set */
524 bool rx_need_yield = false;
525 if (sr & USART_SR_RXNE) {
526 uint8_t byte = dr;
527 if (usart_dev->rx_in_cb) {
528 (void)(usart_dev->rx_in_cb)(usart_dev->rx_in_context, &byte, 1, NULL, &rx_need_yield);
532 /* Check if TXE flag is set */
533 bool tx_need_yield = false;
534 if (sr & USART_SR_TXE) {
535 if (usart_dev->tx_out_cb) {
536 uint8_t b;
537 uint16_t bytes_to_send;
539 bytes_to_send = (usart_dev->tx_out_cb)(usart_dev->tx_out_context, &b, 1, NULL, &tx_need_yield);
541 if (bytes_to_send > 0) {
542 /* Send the byte we've been given */
543 usart_dev->cfg->regs->DR = b;
544 } else {
545 /* No bytes to send, disable TXE interrupt */
546 USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, DISABLE);
548 } else {
549 /* No bytes to send, disable TXE interrupt */
550 USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, DISABLE);
554 #if defined(PIOS_INCLUDE_FREERTOS)
555 if (rx_need_yield || tx_need_yield) {
556 vPortYield();
558 #endif /* PIOS_INCLUDE_FREERTOS */
561 static int32_t PIOS_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param)
563 struct pios_usart_dev *usart_dev = (struct pios_usart_dev *)usart_id;
565 bool valid = PIOS_USART_validate(usart_dev);
567 PIOS_Assert(valid);
569 /* First try board specific IOCTL to allow overriding default functions */
570 if (usart_dev->cfg->ioctl) {
571 int32_t ret = usart_dev->cfg->ioctl(usart_id, ctl, param);
572 if (ret != COM_IOCTL_ENOSYS) {
573 return ret;
577 switch (ctl) {
578 case PIOS_IOCTL_USART_SET_IRQ_PRIO:
579 return PIOS_USART_SetIrqPrio(usart_dev, *(uint8_t *)param);
581 #ifdef PIOS_USART_INVERTER_PORT
582 case PIOS_IOCTL_USART_SET_INVERTED:
583 if (usart_dev->cfg->regs != PIOS_USART_INVERTER_PORT) {
584 return COM_IOCTL_ENOSYS; /* don't know how */
586 GPIO_WriteBit(PIOS_USART_INVERTER_GPIO,
587 PIOS_USART_INVERTER_PIN,
588 (*(enum PIOS_USART_Inverted *)param & PIOS_USART_Inverted_Rx) ? PIOS_USART_INVERTER_ENABLE : PIOS_USART_INVERTER_DISABLE);
590 break;
591 #endif /* PIOS_USART_INVERTER_PORT */
592 case PIOS_IOCTL_USART_GET_DSMBIND:
593 #ifdef PIOS_USART_INVERTER_PORT
594 if (usart_dev->cfg->regs == PIOS_USART_INVERTER_PORT) {
595 return -2; /* do not allow dsm bind on port with inverter */
597 #endif /* otherwise, return RXGPIO */
598 case PIOS_IOCTL_USART_GET_RXGPIO:
599 *(struct stm32_gpio *)param = usart_dev->cfg->rx;
600 break;
601 case PIOS_IOCTL_USART_GET_TXGPIO:
602 *(struct stm32_gpio *)param = usart_dev->cfg->tx;
603 break;
604 case PIOS_IOCTL_USART_SET_HALFDUPLEX:
605 USART_HalfDuplexCmd(usart_dev->cfg->regs, *(bool *)param ? ENABLE : DISABLE);
606 break;
607 case PIOS_IOCTL_USART_LOCK_CONFIG:
608 usart_dev->config_locked = *(bool *)param;
609 break;
610 default:
611 return COM_IOCTL_ENOSYS; /* unknown ioctl */
614 return 0;
617 #endif /* PIOS_INCLUDE_USART */
620 * @}
621 * @}